RSpec accessing application_controller methods such as 'current_user' - ruby-on-rails

I'm trying to stub out a method on my current_user (using a modified restful_authentication auth solution) with rspec. I'm completely unsure of how I can access this method in my controller specs. current_user by itself doesn't work. Do I need to get the controller itself first? How do I do this?
Using rails 2.3.5, rspec 1.3.0 and rspec-rails 1.3.2
# my_controller_spec.rb
require 'spec_helper'
describe MyController do
let(:foos){ # some array of foos }
it "fetches foos of current user" do
current_user.should_receive(:foos).and_return(foos)
get :show
end
end
Produces
NoMethodError in 'ChallengesController fetches foos of current user'
undefined method `current_user' for #<Spec::Rails::Example::ControllerExampleGroup::Subclass_1::Subclass_1::Subclass_2::Subclass_2:0x7194b2f4>

rspec-rails gives you a controller method for use in controller examples. So:
controller.stub!(:current_user).with(:foos).and_return(foos)
ought to work.

how can it know where to find current_user? this should solve it:
subject.current_user.should_receive(:foos).and_return(foos)

I'm not entirely familiar with restful_authentication, just Authlogic and Devise, but it's probably similar in that current_user is a controller method and not an object, which is why calling should_receive on it isn't working as expected (you're setting an expectation on the object that current_user returns, but the method isn't accessible inside the scope of your expectation).
Try this:
stub!(:current_user).and_return(foos)

I read this and tweaked mine a bit. If you simply want to pass in a user object into your Rspec test, you can use this:
First, create a user object within the rspec test. For example:
(use whatever attributes you need or are required to create the user object.)
user = User.create(name: "ted")
(Note: you can also use a factory from FactoryGirl.)
Now, with that user object which is saved into the variable "user", do this within that same Rspec test:
controller.stub!(:current_user).and_return(user)
that should work...

Related

Rails / RSpec: Using :assigns in an observer spec?

I'm logging the changes to a model to use in an activity feed. I have an observer that does this (activerecord dirty):
def before_update(derp)
#changes = derp.changes
end
This abstracts this functionality out of the controller. I want to test this using rspec, so I have this:
it "assigns derp.changes to #changes" do
derp.attribute = 5
#observer.before_update(derp)
expect(assigns(:changes)).to eq(derp.changes)
end
I'm getting this error: undefined method `assigns' for RSpec::ExampleGroups::DerpObserver::BeforeUpdate:0x007fc6e24eb7f8
How can I use assigns in an observer spec? Or, is there another way that I could test that #changes got assigned?
instance_variable_get is what I was looking for.
http://apidock.com/ruby/Object/instance_variable_get
expect(#observer.instance_variable_get(:#changes)).to eq(derp.changes)

How do I pass a block to the Devise create method?

Im using devise token auth (which inherently just uses Devise) and I'm trying to modify the resource object before it gets saved upon user registration. The create method, as defined in the source and explained in user documentation has a yield resource if block_given? line, yet, the following code doesnt work as expected
class RegistrationsController < DeviseTokenAuth::RegistrationsController
def create
puts "this works"
super do |resource|
puts "this doesnt work"
end
end
end
Any idea why?
https://github.com/lynndylanhurley/devise_token_auth/blob/master/app/controllers/devise_token_auth/registrations_controller.rb
This base controller doesn't have block invocation.
Probably you meant https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb
It has block invocation, but it'll not work, because DeviseTokenAuth::RegistrationsController will not pass block to it.
You need some other way to achieve what you want.
Probably paste code from DeviseTokenAuth::RegistrationsController to your custom controller, or fork DeviseTokenAuth gem and patch it.
Don't forget to make PR

Rails 4.1: access current_user in ActionMailer::Preview

Rails 4.1 has a nice way to preview mailers with ActionMailer::Preview. All of my mailers take a user parameter, and I would like to pass in current_user (from Devise) for the preview.
If I try this, it doesn't work.
class SubscriptionsMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/subscriptions_mailer/new
def new
SubscriptionsMailer.new(current_user)
end
end
It returns undefined local variable or method 'current_user' for #<SubscriptionsMailerPreview:0xa6d4ee4>.
I suspect this is because current_user is defined by Devise in ApplicationController, and according to the docs, ActionMailer uses AbstractController::Base. In that case, would storing current_user in a class variable be a bad idea?
Does anyone know how I can use the current_user helper in ActionMailer::Preview?
What would happen if you move your mailer job to the background? How would you get the current user then?
The mailer and its preview should not know about the current_user. The mailer's job is to send the mail to a user it receives. The preview is there to visually demonstrate its behaviour.
Create a new user in your mailer preview, and pass it to the mailer.
def new
user = User.create! # etc...
SubscriptionsMailer.new(user)
end
It doesn't matter who the user is. It matters that it's a user object.
If you want to test that the application will send a mail to the current_user, write a functional test for that.
You are right method defined in Controller won't be available in helper.
These posts can help you:
Where do I put helper methods for ActionMailer views? Access helpers from mailer?
https://www.ruby-forum.com/topic/168949

Rails/devise current_user accessed in model but it's nil

I needed to access the current_user in my another model. I googled and found a few solutions and tried this.
But just one difference: I didn't set the User.current_user in the controller. WHY?
Like in the answer I followed I'm not adding data to my second model from views but by rendering data via a url (with open-uri, it's csv data I'm fetching).
So in my second model I do:
Person.create(username: User.current_user.username)
It gives:
NoMethodError: undefined method `username' for nil:NilClass
which isn't working (which is obvious I guess). In console when I do User.current_user it shows:
1.9.3p448 :002 > User.current_user
=> nil
I think why it isn't working is because I'm accessing the User.current_user directly from model and model cannot get the current_user unless it is given that. (right?)
But this would definitely work if I access it via a login page and set the User.current_user in the controller.
But as I'm directly fetching the data from url, I'm directly making new entries for my Person model in model itself.
So how do I set the User.current_user?
Is there any workaround for this? Edit's for the question's title are required.
current_user is available by default as a helper method within Devise. From the documentation:
# For the current signed-in user, this helper is available:
current_user
The current_user isn't accessed directly via the model, per se, but rather, though the Devise module, which looks up the User object that is logged into the current session, and then returns to current_user.
Thus, the current user isn't accessed via User.current_user (there is no current_user method on User, as the error message is saying). You access it purely by invoking the current_user helper method within a controller or view.
UPDATE:
You're well advised to keep your controller and model layers separate. One way of doing what you've proposed is to create a class function on the Person model wherein you explicitly pass the username of your User object from within your controller:
# in your controller
Person.create_with_username(:username => current_user.username)
# app/models/person.rb
def self.create_with_username(username)
self.create(username)
end

How can I access helper methods in my decorator spec files using Draper 0.14.0

Currently in my spec/decorators/product_decorator_spec.rb, I have the following:
require 'spec_helper'
describe ProductDecorator do
let(:product) { FactoryGirl.create(:product) }
subject do
ProductDecorator.first
end
before do
product
end
it 'should render the name attribute with a link to the product page' do
subject.name.should == h.link_to(product.name, 'test')
end
end
When I run my spec I get the following:
F.....
Failures:
1) ProductDecorator should render the name attribute with a link to the product page
Failure/Error: subject.name.should == h.link_to(product.name, 'resr')
NameError:
undefined local variable or method `h' for #<RSpec::Core::ExampleGroup::Nested_2:0x007fbbf212c8b0>
# ./spec/decorators/product_decorator_spec.rb:15:in `block (2 levels) in <top (required)>'
Finished in 0.98531 seconds
6 examples, 1 failure
Failed examples:
rspec ./spec/decorators/product_decorator_spec.rb:14 # ProductDecorator should render the name attribute with a link to the product page
According to the documentation, specs placed in the decorator folder should have access to the helper method, however my spec does not. I've also tried manually tagging my specs, but doesn't seem to have any effect.
Thanks for looking.
if you want to access the helper, you can do it via your_decorator.h.link_to.
when you are setting the subject, you will need to make sure that the thing you are calling will get routed to the helper, there is nothing injected into your rspec example!
in your example it would be subject.h.link_to for calling a helper method.
i also think that there are a lot of wired things in your spec. your usage of let, subject and before are kind of disturbing for me...
here is a nice writeup about how to write clean rspec: http://eggsonbread.com/2010/03/28/my-rspec-best-practices-and-tips/
I've encountered the same issue, where calling helper methods on the decorator's helper proxy (.h) doesn't work in test (in Draper 1.3). I ended up working around it with this, though I'm not very pleased with it:
my_decorated_object.h.extend ApplicationHelper
Your mileage may vary depending on how many controller features you access in your helper.

Resources