I'm pretty new to Rails. I have been developing my app with RSpec. I have just followed a tutorial for Facebooker2 and added the before_filter for authentication.
#app/controller/application_controller.rb
before_filter :ensure_authenticated
However, my specs such as the one below failed because there's no valid session which is understandable.
#spec/controllers/answers_controller_spec.rb
describe "GET index" do
it "assigns all answers as #answers" do
get :index, {}, valid_session
assigns(:answers).should include(answers(:reading))
end
end
But I can't seem to find a way to fake a valid session for rspec to use in the following function.
#spec/controllers/answers_controller_spec.rb
def valid_session
{}
end
Is there a way at all? If not, what is the rails way of doing things for such a case?
If you aren't concerned about testing the actual authentication and just want to simulate a valid session, you could stub out the filter:
controller.stub(:ensure_authenticated).and_return(true)
EDIT: you may need ApplicationController.stub(...)
Related
I am learning rails using the teamtreehouse tutorial. The tutorial uses 3.1 but I am trying to learn 4.0, and as a result I have run into a difficulty presumably because rails 4 forces of the use of strong parameters. I have two models, a users model and a statuses model. I have used devise to create authentication for users, and have included new parameters. They are :first_name, :last_name, and :profile_name. I have created a relationship between users and statuses.
Currently the user sign-up with the new parameters is working; i can access them using for instance current_user.last_name. However, I want to show the profile_name of the user that created the post on the statuses index view(each user does not yet have a separate page). I want to do this using
status.user.profile_name
However it just shows up blank. If I do
status.user.email(which is a preconfigured devise parameter), it shows up no problem. I am guessing I have to whitelist these parameters in some controller but I don't know where or how.
Thanks
I think, here you will find your answer: https://github.com/plataformatec/devise/tree/rails4#strong-parameters
Based on above link, I think you should insert something like this in your ApplicationController:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:user) { |u| u.permit(:profile_name) }
end
end
And I already suggested in a previous question...
Strong parameters with Rails and Devise
...that you can create your own controller which could extend devise own controller. There is a gist for that:
https://gist.github.com/bluemont/e304e65e7e15d77d3cb9
A little bit more details in Devise doc: https://github.com/plataformatec/devise/tree/rails4#configuring-controllers
I am using scaffold on ruby on rails, and its great and all, makes everything simpler, but I dont understand one thing and the books or the web dont have a clear solution.
For exmaple, I use scaffold and I create table user and I can make /user/1 and I will see the user with the ID 1 , and if i make /user/edit/1 I will edit user with ID number 1, but on the controller the code its like this
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
According the MVC Ive worked, the controller is the first in respond, so, in some way I should be able to indicate to use the show method, but how? I dont have anything else added on my routes file. any idea??
The default routes are "HTTP Verb: GET, Path: /photos/:id, Action: show, Used For: display a specific photo". See the documentation.
Scaffold add resource :users in your routes.rb file `. This actually enables all RESTfull routes. You can see the default routes in this table (bellow). This is what is defined as convention over configuration, and it is because of this that rails is magical. Once you master a few conventions, your will be able to do more with less.
table http://i.imm.io/150CI.png
By the way, this is a really nice site to use if you are planning to learn Rails. I'm not aware of a better source, even books.
I'm using cucumber to test my rails 3.1 application and i'm using devise for authentication.
I need to test if current user email is the same with the one used during authorization.
The problem is that devise helpers are not available in cucumber step definition.
Is there any solution to make devise helpers available in cucumber step definitions?
i tried this:
Cucumber::Rails::World.send('define_method', 'current_user') do
#current_user ||= (session[:user] && User.find(session[:user])) || :false
end
but that didn't help.
Add this to the step definitions file that needs to use it:
World(Devise::TestHelpers)
While this makes the 'sign_in' and 'sign_out' methods available, they can't actually be used from Cucumber, so this DOES NOT WORK. The comments at the top of devise's file says "Do not use Devise::TestHelpers in integration tests". See: https://github.com/plataformatec/devise/blob/master/lib/devise/test_helpers.rb
Unfortunately, cucumber steps don't have access to the web request object and session parameters. It appears the only way to do this is to repeatedly perform the login web requests at the start of each scenario. Boring. I find it odd that cucumber can directly manipulate the test rails app's database but not the web request/session. In any case, this old post shows a good example of refactoring steps to be in a module that can be shared by many steps easily: http://drnicwilliams.com/2009/04/15/cucumber-building-a-better-world-object/
If anyone else has an answer for how a scenario can set the logged in state without having to do all the capybara web calls, I'd love to hear it.
You can do this to stub log ins in Cucumber:
https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara
put the lines in support/env.rb:
include Warden::Test::Helpers
After do
Warden.test_reset!
end
then you can do:
user = create :user
login_as :user, scope: :user
BUT, the login_as helper does not redirect you to the next page after logging you in. It just logs you in.
So you must explicitly go to the next page you are testing as a logged in user.
So you must do another step to explicitly do that, e.g. visit '/'
Something that may help is https://github.com/ngty/cross-stub - this allows you to stub methods cross process, which is necessary for cucumber testing sometimes
I've used CanCan before and it's great, but sometimes I don't need such customizable role management. Sometimes I just need to distinguish between an admin and everyone else. So, I usually just write an :authenticate_admin! method for the controllers and methods I need to protect.
What I've found a little more complicated is ensuring that users can only manage resources they own. Say, I user can create posts, I don't want them to be able to update or destroy a post they didn't create. So, I'm curious about how others have gone about handling this in the most DRY way possible.
Here's what I've done, off the top of my head:
In the application controller:
def user_can?(resource_user_id, current_user_id)
return true if current_user.is_admin
return true if resource_user_id == current_user_id
end
Then, in the controller in question, I do something like
before_filter :can_manage_project?, :except => [:new, :create]
and
protected
def can_manage_project?
#project = Project.find(params[:id])
return true if user_can?(#project.user_id, current_user.id)
redirect_to user_path(current_user), :flash => {:error => "Sorry, you're not allowed to do that."}
end
Seems like a lot of code for a relatively simply task. How have you gone about handling this task? I'm sure there's a more elegant solution -- short of using a gem or plugin.
My first thought would be to abstract out a tiny bit and mix in an is_manageable? method into models via a acts_as_user_manageable-type doodad. Resource controllers would get a manageable_by_current_user? filter (I'm not sure how I'd do that automagically yet). is_manageable? could encapsulate arbitrary rules, so it would be able to handle things like admin flags etc.
I'd have to play a bit to see what implementation I liked the most, but a solution like this seems pretty reasonable, and probably something that a lot of people would dig for projects that don't need the level of control the canonical solutions provide.
Capybara is confusing me. If I use Capybara in combination with Ruby on Rails 3 and RSpec 2, then in RSpec request tests, the following matcher works:
response.body.should have_selector "div.some_class"
The response object has the class ActionDispatch::TestResponse. But the following line, which should work officially, does not work:
page.should have_selector "div.some_class"
The page object has the class Capybara::Session. In which cases do you have to use the response.body object and when do you have to use a page object ?
So I just ran into similar, and this is I think what's going on:
It depends on code you didn't include here of how you visit the page. I'm writing an rspec request spec.
If I retrieve the page with rspec's own:
get '/some/path'
then response.body.should have_selector works as you say, but page.should does not.
To make Capybara 'page' work (and to make Capybara interactions like click_button or fill_in work), instead of retrieving with rspec's 'get', you need to retrieve with Capybara's 'visit':
visit '/some/path'
page.should have_selector("works")
'page', a capybara method, only gets set when using 'visit', a capybara method.
This does get confusing, all the mixing and matching of different libraries involved in rails testing.
You would use response when you want to use the standard rails methods. And, alternately, you'd use page when you want to use the capybara methods. In capybara you'd most likely use have_css in the example given.