Rails 4 + Merit + Devise: set a badge for user after registration - ruby-on-rails-4

I have a trouble at this situation. I followed this manual, but it don't helped me.
Here's my files:
routes.rb:
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks', registrations: 'registrations' }
merit.rb:
Merit.setup do |config|
config.checks_on_each_request = true
end
Merit::Badge.create!(
id: 1,
name: 'just-registered',
description: 'Badge for register'
)
badge_rules.rb
module Merit
class BadgeRules
include Merit::BadgeRulesMethods
def initialize
grant_on 'registrations#create', badge: 'just-registered', model_name: 'User'
end
end
end
registrations_controller.rb
def create
#user = build_resource
super
end
And if make sense - when user is registered, to merit_actions table added a new record with target_model = 'registrations', not 'users'
Can someone tell me, what i'm doing wrong ?

That's expected behavior, merit_actions is internal to the gem and saves controller_path as it's target_model attribute. It is confusing, but it shouldn't affect your application. Is the badge being granted?

Related

Crud operation "Delete" don't works in my first project in ruby on rails

I'm implementing in my first project the crud operation "delete", but the system take the command as a "get", whitout errors.
this is the controller:
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
#GET /movies/:id
def show
id = params[:id]
#movie = Movie.find(id)
#render plain: 'show'+params[:id]
end
#POST /movies/
# skip_before_action :verify_autenticity_token:
def create
#movie = Movie.create!(params[:movie].permit(:title, :rating, :description, :realease_date))
flash[:notice] = "#{#movie.title} was successfully created."
redirect_to movies_path
end
#new
def new
end
def edit
id = params[:id]
#movie = Movie.find(id)
end
def update
id = params[:id]
#movie = Movie.find(id)
if #movie.update_attributes!(params[:movie].permit(:title,:rating,:realease_date))
flash[:notice] = "#{#movie.title} has been edited."
redirect_to movies_path
end
end
def destroy
id = params[:id]
#movie = Movie.find(id)
#movie.destroy
flash[:notice] = "#{#movie.title} has been deleted."
redirect_to movies_path
end
end
this is the view where is possible call "Delete" operation:
%h2 Details about #{#movie.title}
%ul#details
%li
Rating:
= #movie.rating
%li
Released on:
= #movie.realease_date#.strftime("%B %d, %Y")
%h3 Description:
%p#description= #movie.description
%h4 Reviews:
- if #movie.reviews.empty?
%p
No reviews for this movie...
-else
- #movie.reviews.each do |r|
- u = Moviegoer.find(r.moviegoer_id)
<b>#{r.vote}</b> (<i>#{Moviegoer.find(r.moviegoer_id).name}</i>) #{r.message} <br />
= link_to 'Add review', new_movie_review_path(#movie)
<br/><br/>
#{link_to 'Edit info', edit_movie_path(#movie)} - #{link_to 'Delete', movie_path(#movie), :method => :delete} - #{link_to 'Back to movie list', movies_path}
The problem probably is in the last line, because in server command line "Delete" isn't calls.
this is the server response (is the last GET that is execute when i press "Delete" on the browser) :
enter image description here
file routes.rb:
Rails.application.routes.draw do
resources :movies do
resources :reviews, only: [:new, :create, :destroy]
end
resources :moviegoers
root :to => redirect('/movies')
end
Result of command "rake routes":
Prefix Verb URI Pattern Controller#Action
movie_reviews POST /movies/:movie_id/reviews(.:format) reviews#create
new_movie_review GET /movies/:movie_id/reviews/new(.:format) reviews#new
movie_review DELETE /movies/:movie_id/reviews/:id(.:format) reviews#destroy
movies GET /movies(.:format) movies#index
POST /movies(.:format) movies#create
new_movie GET /movies/new(.:format) movies#new
edit_movie GET /movies/:id/edit(.:format) movies#edit
movie GET /movies/:id(.:format) movies#show
PATCH /movies/:id(.:format) movies#update
PUT /movies/:id(.:format) movies#update
DELETE /movies/:id(.:format) movies#destroy
moviegoers GET /moviegoers(.:format) moviegoers#index
POST /moviegoers(.:format) moviegoers#create
new_moviegoer GET /moviegoers/new(.:format) moviegoers#new
edit_moviegoer GET /moviegoers/:id/edit(.:format) moviegoers#edit
moviegoer GET /moviegoers/:id(.:format) moviegoers#show
PATCH /moviegoers/:id(.:format) moviegoers#update
PUT /moviegoers/:id(.:format) moviegoers#update
DELETE /moviegoers/:id(.:format) moviegoers#destroy
root GET / redirect(301, /movies)
rails_service_blob GET /rails/active_storage/blobs/:signed_id /*filename(.:format) active_storage/blobs#show
rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage /direct_uploads(.:format) active_storage/direct_uploads#create
It's hard to say exactly what's going on without seeing the corresponding routes. You might try running rake routes to see what the available routes are.
Based on the comments in your controller, I'm guessing you probably have to do something like pluralize the path link_to 'Delete', movies_path(id: #movie.id), method: :delete, but that would only fix the problem if your resource routes are misconfigured.
In order for the link to work as you have it configured your route file would either have to contain resources :movies, or a specially configured route to map to the delete action.

Rspec/Capybara: Devise user 'dissapears' after logging in

I'm having a bizarre problem where I create an admin user for an Rspec/Capybara test and the user is mysteriously deleted after logging in. When I run my test, the user is created and successfully logged in. However when Capybara visits the admin_categories_path, the test fails. Rails raises an exception because current_user is not defined. When I insert a binding.pry, I can see that the user exists up until they are logged in, at which point the user disappears from the test database, causing current_user to be undefined, and thereby triggering an exception. I'm at a loss as to how/why this is happening.
UPDATE: I've gotten past the problem of the user being deleted. Now when Capybara sees the admin_categories_path page, category isn't displayed. Inserting a binding.pry reveals that category is present in the database.
When I launch the app and log in manually, I have no problems accessing admin_categories_path.
Here is my spec file:
require 'rails_helper'
feature 'admin edits category', %Q{
As an admin, I want to edit a category or subcategory, so that it better
represents the content under it.
Acceptance Criteria:
* [X] - I can edit the name of a category inline.
* [X] - I can edit the name of a subcategory inline.
} do
let(:admin) do
FactoryGirl.create(:user, admin: true)
end
let(:category) do
FactoryGirl.create(:category)
end
scenario 'admin edits category title', js: true, focus: true do
login_as(admin)
visit admin_categories_path
bip_area category, :name, 'Test Category'
expect(page).to have_content 'Test Category'
end
end
Here is my helper file authentication.rd:
module Helpers
module Authentication
def log_in_as(user)
visit new_user_session_path
within "#new_user" do
fill_in 'user[email]', with: user.email
fill_in 'user[password]', with: user.password
click_on "Log in"
end
end
end
RSpec.configure do |config|
config.include Authentication, :type => :feature
end
end
Here is my user factory:
require 'factory_girl'
FactoryGirl.define do
factory :user do
sequence(:email) {|n| "lafiel.abriel#{n}#abhnation.com" }
username
password 'password'
password_confirmation 'password'
end
factory :category do
sequence(:name) { |n| "Category ##{n}" }
parent_id nil
display_index 1
user
end
sequence :username do |n|
"Lafiel_Abriel_#{n}"
end
end
And here is my application_controller.rd where the exception is triggered:
module Admin
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :reject_unless_admin
layout 'admin/layouts/application'
protect_from_forgery with: :exception
helper :avatar, :devise, :admin
protected
def reject_unless_admin
unless current_user && current_user.admin?
raise ActionController::RoutingError.new('404: Not Found')
end
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << [
:avatar,
:remote_avatar_url,
:email,
:username,
:first_name,
:last_name,
:age,
:website,
:password,
:password_confirmation,
:current_password
]
end
end
end
Any help/insight is greatly appreciated. Thanks.
If I recall correctly, this problem had something to do with the test database schema being out of sync with the development database. Try running rake db:test:prepare to ensure your test schema matches your development schema.
In my specific case, I had a two problems to overcome.
The first problem occurred when I created a category and an admin in a let block. Those needed to be placed in a before block so that they were created before the test executed. When I placed those variables in let blocks, they were not being created until the first time they were called in the test. So when I logged in as an admin, the admin variable was being passed to my login_as helper method before it was saved to the database. The same is true for the category variable.
This code doesn't work for me:
let(:admin) do
FactoryGirl.create(:user, admin: true)
end
let(:category) do
FactoryGirl.create(:category)
end
scenario 'admin edits category title', js: true, focus: true do
login_as(admin)
visit admin_categories_path
bip_area category, :name, 'Test Category'
expect(page).to have_content 'Test Category'
end
This is solution I used to overcome the first problem:
before(:each) do
#admin = FactoryGirl.create(:user, admin: true)
#category = FactoryGirl.create(:category, user: #admin)
end
scenario 'admin edits category title', js: true do
skip "Doesn't work yet."
login_as(#admin)
visit admin_categories_path
wait_for_ajax
bip_text #category, :name, 'Test Category'
expect(page).to have_content 'Test Category'
end
The second problem is that when my test hits the admin/categories_controller.rb, Category.all returns an empty array, even though #category.save! and #category.valid? return true when I test my before block. I was never able to find a solution to the problem and ended up putting the test on ice.
I think part of the problem is that the documentation for the Best-in-Place gem is not very good. I used it at the time because it was an easy solution to my problem. Going forward though, I would use something like angular for this use-case. The documentation is much better and it's not a black box like a lot of gems are.
I'm not sure what bip_area does, but since your test says that it's editing a category I assume you are expecting the category to be present on the page when you visit admin_categories_path. When you visit that path however category has not yet been created since you are using 'let' which is lazily evaluated (created at time of first use of the variable), so it would not be shown on the screen for you to edit. Using binding.pry and then looking at that variable would actually create it, so it might be confusing you into thinking it was there. You can use 'let!' instead which will force the variable to be created before each test instead of lazily evaluating it.

Getting tripped up by verify_partial_doubles with rails 4 and rspec 3

I'm using authlogic for my user authentication and in my ApplicationController I have "current_user", "current_user_session", etc. defined and set as helper_methods.
I have an extremely simple view spec for my main index:
RSpec.describe "main/index.html.erb", :type => :view do
context "when not logged in" do
before do
allow(view).to receive(:current_user).and_return(nil)
end
it "has an h1" do
render
expect(rendered).to include('h1')
end
end
end
The problem is that if "mocks.verify_partial_doubles = true" in my config then this causes an impressively massive error as it dumps an entire object and then says at the bottom:
1) main/index.html.erb when not logged in has an h1
Failure/Error: allow(view).to receive(:current_user).and_return(nil)
#<#<Class:0x00000104c249d0>:.........
#rendered_views={}>> does not implement: current_user
Of course, it is recommended that verify_partial_doubles is set to true, but in doing so this breaks. I pulled this straight from the documentation:
https://www.relishapp.com/rspec/rspec-rails/v/3-1/docs/view-specs/view-spec#passing-view-spec-that-stubs-a-helper-method
If the method appears in ApplicationHelper it'll work. But if it's in ApplicationController and defined as a helper_method there's no such luck:
helper_method :current_user, ...
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.record
end
I want the protection that verify_partial_doubles provides, how can I work around this?
This is a known issue and the only way to get it working is to extract the methods into a module and include it in your view helpers and the controller.
More information at: https://github.com/rspec/rspec-rails/issues/1076
You can disable double verification for views as follows:
RSpec.configure do |config|
config.before(:each, type: :view) do
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = false
end
end
config.after(:each, type: :view) do
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
end
This way you'll be able to keep stubbing view methods with:
allow(view).to receive(:current_user).and_return(nil)
More information at: https://github.com/rspec/rspec-rails/issues/1076

ActiveModel::ForbiddenAttributesError + cancan + rails 4 + model with scoped controller

I m using cancan(1.6.10) with rails 4.0.0. I have a model called 'App'(not scoped) and a controller Admin::AppsController(its scoped. ie app/controllers/admin/apps_controller).
the controller code is as
class Admin::AppsController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource class: App
def index
end
#CRUD methods and some other custom methods
...
private
def app_params
params.require(:app).permit(:name, :description, :author, :url_path, :validated, :active, :version)
end
end
I m getting error when i try to create a 'app'.
ActiveModel::ForbiddenAttributesError - ActiveModel::ForbiddenAttributesError:
activemodel (4.0.0) lib/active_model/forbidden_attributes_protection.rb:21:in `sanitize_for_mass_assignment'
I added
before_filter do
resource = controller_path.singularize.gsub('/', '_').to_sym
method = "#{resource}_params"
params[resource] &&= send(method) if respond_to?(method, true)
end
as specified in https://github.com/ryanb/cancan/issues/835#issuecomment-18663815 but still getting the above error.
Using name spaces. Please try to change your code to this one below. I had same issue after #JiriKolarik suggested his solution to work with name spaces. I hope it helps.
before_filter do
resource = controller_name.singularize.to_sym
method = "#{resource}_params"
params[resource] &&= send(method) if respond_to?(method, true)
end
if you use this workflow
before_filter do
resource = controller_path.singularize.gsub('/', '_').to_sym
method = "#{resource}_params"
params[resource] &&= send(method) if respond_to?(method, true)
end
then your params method should look like this
def admin_app_params
params.require(:admin_app).permit(:name, :description, :author, :url_path, :validated, :active, :version)
end
The reason why, it's because form generators (form_form, simple_form) generate params with namespace_resource
So if you have Blog::Post, form generator will create params like this
{ "blog_post"=>{"title"=>"Post"}, "commit"=>"Create", "action"=>"create", "controller"=>"blog/posts", "locale"=>"en"}
And this is how before filter works:
before_filter do
resource = controller_path.singularize.gsub('/', '_').to_sym # => 'blog/posts' => 'blog/post' => 'blog_post' => :blog_post
method = "#{resource}_params" # => 'blog_post_params'
params[resource] &&= send(method) if respond_to?(method, true) # => params[:blog_post]
end
If you need read :blog_post from params, solution above will not work. If you need read :post from params, then this solution will not work, if your controller will be blog/post
cancan just does not work with the strong parameter. While there is a new gem cancancan which works well without any code change.

how do you stub a local variable in an rspec controller test

I've just implemented OmniAuth (using Ryan Bates' Screencast http://asciicasts.com/episodes/235-omniauth-part-1) and am writing Rspec tests for the functionality and have ran into trouble testing the authentifications#create action. I'm at quite a loss as to how to test this one -- in particular how to stub the local variable omniauth. No matter what I try I keep can't get any tests to work.
Taking a cut down version of the action, how would you test that a new is called on User for example
#cut down version of the authentifications controller code I am attempting to test
def create
omniauth = request.env["omniauth.auth"]
authentification = Authentification.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
....
user = User.new
....
end
#example test
it "should create a new user" do
subject.stub_chain(:request,:env) {{"omniauth.auth" => {'provider' =>1, 'uid' => 2}}}
User.should_receive(:new)
post :create
end
I Did that :
class SessionsController < ApplicationController
def create
#user = User.find_by_auth_hash(auth_hash)
end
def auth_hash
request.env['omniauth.auth']
end
end
describe SessionsController do
it 'should allow login' do
controller.stub!(:auth_hash).and_return({'provider' => 'twitter', 'uid' => '1234'})
get :create, :provider => 'twitter'
assigns(:user).should_not be_nil
end
end
Hope that helps.