I have a model group.rb and then a controller group_invitations.rb which is modeless.
GroupInvitationsController
before_filter :find_group_by_group_id
before_filter :authenticate_user!
before_filter :current_ability
authorize_resource :class => false
def current_ability
#current_ability ||= Ability.new(current_user, #group)
end
When I write a rspec for this:
it "should be able to create" do
ability = Ability.new(nil)
ability.should be_able_to(:create, GroupInvitation.new)
end
rspec then errors with:
NameError:
uninitialized constant GroupInvitation
How do I setup rspec to test this modeless controller? Thanks
You need to call #ability.should be_able_to(:create, :group_invitation). You can read about what is authorized when using a model-less controller in the documentation.
This is the relevant section:
class ToolsController < ApplicationController
authorize_resource :class => false
def show
# automatically calls authorize!(:show, :tool)
end
end
Related
I have a subscribers section in my application with several controllers which inherited from Subscribers::BaseController
Subscribers::BaseController has a before_action :require_subscription
class Subscribers::BaseController < ApplicationController
before_action :require_subscription, if: :require_subscription?
private
def require_subscription
RequireSubscriptionService.call(current_user)
end
def require_subscription?
# several conditions
end
end
And other controllers for example
class Subscribers::EventsController < Subscribers::BaseController
skip_before_action :require_subscription, only: :other_action
def index
end
def show
end
def other_action
end
end
What is the best way to test, that before_action :require_subscription will be called if it necessary in each action with MiniTest
Usually I use Rspec, and I can use expect matcher in this case
For example
describe 'Subscribers::EventsController' do
describe '.index' do
expect_any_instance_of(described_class).to receive(:require_subscription).and_return(:return_value)
subject
end
describe '.other_action' do
expect_any_instance_of(described_class).not_to receive(:require_subscription)
subject
end
end
But how to test this stuff with MiniTest?
i'm a beginner in ruby on rails(and english :)), and i'm trying to use functional test but i had an error at fist
1)Error:
test_should_get_new(MicropostControllerTest)
NoMethodError: undefined method 'microposts' for nil:NilClass
My micropost_controller_test.rb
require 'test_helper'
class MicropostControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end
end
My micropost_controller.rb
class MicropostController < ApplicationController
def new
#post = Micropost.new
#posts = current_user.microposts.all
end
def create
#post = current_user.microposts.create(:content => params[:content])
logger.debug "New post: #{#post.attributes.inspect}"
logger.debug "Post should be valid: #{#post.valid?}"
if #post
redirect_to micropost_new_path
else
end
end
end
I tried to put something in microposts.yml but it didn't work.
So, where i can find microposts method for functional test and how do i fix that?? Please help me?
p/s: My app still work in localhost
If you are using Devise for user authentication then you need to authenticate and set current_user in your MicropostController, by for instance having a before_action as follows:
class MicropostController < ApplicationController
before_action :authenticate_user!
def new
#post = Micropost.new
#posts = current_user.microposts.all
end
# rest of the code
end
In your test you need to import devise test helpers as follows, if you haven't done it in your test_helper
class MicropostControllerTest < ActionController::TestCase
include Devise::TestHelpers
end
You can then use the sign_in method to sign in a user using Fixtures in your test. search for some tutorials on that or check the response here to get some clue: Functional testing with Rails and Devise. What to put in my fixtures?
I have defined a helper method as such (for my rails engine):
module Xaaron
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
helper_method :current_user
helper_method :authenticate_user!
def current_user
#current_user ||= Xaaron::User.find_by_auth_token(cookies[:auth_token]) if cookies[:auth_token]
end
def authenticate_user!
if current_user
true
else
redirect_to xaaron.login_path
false
end
end
protected
def record_not_found
flash[:error] = 'Could not find specified role'
redirect_to xaaron.record_not_found_path
true
end
end
end
As far as I know everything above is correct in terms of creating helper methods. So now I need to use this helper method:
module Xaaron
class ApiKeysController < ActionController::Base
before_action :authenticate_user!
def index
#api_key = Xaaron::ApiKey.where(:user_id => current_user.id)
end
def create
#api_key = Xaaron::ApiKey.new(:user_id => current_user.id, :api_key => SecureRandom.hex(16))
create_api_key(#api_key)
end
def destroy
Xaaron::ApiKey.find(params[:id]).destroy
flash[:notice] = 'Api Key has been deleted.'
redirect_to xarron.api_keys_path
end
end
end
As you can see, before every action the user must be authenticated. So the authenticat_user!
method is then called.
Lets write a test for this
it "should not create an api key for those not logged in" do
post :create
expect(response).to redirect_to xaaron.login_path
end
This, we expect, to send us back to the login path because we are not signed in, and as you will recall we are using authenticate before every action in the API Controller. What do we get instead:
1) Xaaron::ApiKeysController#create should not create an api key for those not logged in
Failure/Error: post :create
NoMethodError:
undefined method `authenticate_user!' for #<Xaaron::ApiKeysController:0x007f898e908a98>
# ./spec/controllers/api_keys_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
Last I checked the way I defined a helper method is how rails casts has done it, how other stack questions have done it and how rails docs states to do it - unless I missed some majour step - why isn't this working?
Maybe I haven't seen a helper method set up like this before (I'm new to rails) but the helper methods I've seen are defined without controllers.
Usually I see a file like this in the helpers folder
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def current_user=(user)
#current_user = user
end
...
and then
include SessionsHelper
In the application controller.
To me it looks like you're calling the controller a helper method, I'm not sure what the benefits of that would be - but I suppose I wouldn't.
Sorry if this wasn't helpful
View spec failing because the ApplicationController method, logged_in?, wants a user to be returned.
Not sure how to spec this. Currently in before(:each) I have:
controller.stub!(:logged_in?).and_return(FactoryGirl.create(:active_user))
#ballots = FactoryGirl.create_list(:full_ballot, 2)
which isn't working:
Failure/Error: render
ActionView::Template::Error:
undefined method 'logged_in?' for #<#<Class:0x007f9c908e4b10>:0x007f9c90873b68>
FWIW: :active_user is the user factory for the user that is attached to the :full_ballot
Update: As requested:
class ApplicationController < ActionController::Base
...
def current_user
#current_user ||= User.find(cookies[:id_token]) if cookies[:id_token]
end
def logged_in?
current_user
end
...
end
See how devise test helpers do it. It looks like you can define this method before tests and it should work:
def logged_in?
FactoryGirl.create :active_user
end
I have an application that detects the subdomain on a request and sets the result to a variable.
e.g.
before_filter :get_trust_from_subdomain
def get_trust_from_subdomain
#selected_trust = "test"
end
How can I test this with Test::Unit / Shoulda? I don't see a way of getting into ApplicationController and seeing what's set...
The assigns method should allow you to query the value of #selected_trust. To assert that its value equals "test" as follows:
assert_equal 'test', assigns('selected_trust')
Given a controller foo_controller.rb
class FooController < ApplicationController
before_filter :get_trust_from_subdomain
def get_trust_from_subdomain
#selected_trust = "test"
end
def index
render :text => 'Hello world'
end
end
one might write a functional test as follows in foo_controller_test.rb:
class FooControllerTest < ActionController::TestCase
def test_index
get :index
assert #response.body.include?('Hello world')
assert_equal 'test', assigns('selected_trust')
end
end
Related to comment: note that the filter can be placed in ApplicationController and then any derived controller will also inherit this filter behaviour:
class ApplicationController < ActionController::Base
before_filter :get_trust_from_subdomain
def get_trust_from_subdomain
#selected_trust = "test"
end
end
class FooController < ApplicationController
# get_trust_from_subdomain filter will run before this action.
def index
render :text => 'Hello world'
end
end
ApplicationController is global, have you considered writing a Rack Middleware instead? Way easier to test.
I've opted for this in another controller in the application:
require 'test_helper'
class HomeControllerTest < ActionController::TestCase
fast_context 'a GET to :index' do
setup do
Factory :trust
get :index
end
should respond_with :success
should 'set the trust correctly' do
assert_equal 'test', assigns(:selected_trust)
end
end
end