Passing controller method attributes in before_filter methods in Rails 3 - ruby-on-rails-3

I'm trying to only allow access to galleries by users who have permission to view them. Galleries have many shared_users through permissions, and vice versa. Galleries also have only one owner. Owners and shared users are both of the User class. This all works fine. The issue that I'm having, however, is with my access filters.
I'm using the following code to see if a user is allowed to see the gallery they are trying to access:
def authenticate_viewers!
if user_signed_in? && current_user.can_view?(#gallery)
return true
end
redirect_to root_url,
:notice => "You must have permission to view this gallery."
return false
end
As you can see, can_view? requires the #gallery that I'm setting up in the show method, but a before_filter won't let you access the attributes set up in the method, since it resolves before the method executes. Using an after_filter works, as long as an unauthorized user doesn't try to view the gallery. If it does, I get a DoubleRender error, since after_filter allows the page to render, then tries to redirect.
I just thought that I could perhaps use params[:id] instead of #gallery, though I haven't tried it yet, and ultimately this may be more efficient (passing an integer instead of an object). In any case, is there a way to make my current code work? or is it in my best interest to switch to using the params (if that's even going to work)?

Wow, okay. It's really helpful just to start writing questions here on SO, because as I do, I typically get a brainstorm of how to solve the problem. Instead of using the #gallery object, I just use a Gallery.find(params[:id]) and everything works like a charm. Thank God I don't have to rewrite all my code.

Related

can?(:update) returning false, but cancan not restricting edit / updates on resource with inherited_resources gem

I'm using cancan with inherited resources and I'm encountering a strange issue (possibly bug?) where I defined a permission for an edit permission for a user and suddenly they are authorized to access the /edit action despite the ability returning false. So here's the behavior I'm experiencing.
class VenuesController < ApplicationController
inherit_resources
authorize_resource
end
Without an ability defined, my non-admin user is redirected from /venues/1/edit to the homepage. However, once I define an :update ability, I am not redirected whether the ability returns true or false. Here is the ability I want to define:
ability.rb
can :update, Venue do |venue|
venue.admin_ids.map{|a| a.to_s}.include? user.id.to_s
end
This returns the correct value as I can see with my test as well as with a sanity check inside my view:
venues/edit.html.haml
= can? :update, #venue
#returns false
So, if I'm inside the edit action and my view says "I cannot update", shouldn't cancan be redirecting me from this page? As a double-sanity-check, I tried
can :update, Venue do |venue|
false
end
and still no luck... I just find it strange that without any ability definition whatsoever, I'm redirected, but when I define an ability that returns false, I'm not redirected despite the view layer appropriately telling me I cannot edit. Any ideas? Is this a bug? Am I doing something wrong?
Furthermore, not only am I able to see the edit action, but actually make put requests to the resource and the resource saves.

Creating an action inside a controller, after it has been generated

I am working on a rails app, and have generated a Controller via
rails g controller Pics index upload
but now I would like to add another action
delete
do I do this by manually adding a delete method in the Pics controller?
Or do I need to run another generation. My concern is that by adding manually something may not get included (not sure what it would be, but something under the hood.)
Is this the best way of adding a new action to a generated controller?
If you add manually, just make sure you have the right route on your routes.rb.
Let's say you create your delete action inside your Pics controller.
def delete
# do stuff
end
On your routes.rb, you need to append the route to your resource like this, remembering to analyse if it is a resource that acts upon a member of your resource, or a collection. (More about this you can read on this guide http://guides.rubyonrails.org/routing.html#adding-more-restful-actions).
resource :pics do
collection do
post :delete
end
end
Or
resource :pics do
member do
post :delete
end
end
Remember that all RESTFUL actions are handled by default by the rails router, again, try to read the guide i showed earlier for precise information about the topic. Hope it helps.

Devise: Load a partial instead of showing a notice for non confirmed members

Is there a way to load a view for no confirmed users that login?
Default behaviour is to show a notice: " You have to confirm your account before continuing."
I tried
overrule the sessions#create method of devise checking for current_user.confirmed_at.blank?
in the after_singin_path check for current_user.confirmed_at.blank? and render the view instead
My goal is to render a custom view instead of the notice but cannot hook into the right location. Who knows how to accomplish this? thx!
You can simply copy the code from the devise github and place in your controllers/devise. then change any action or method you want to.
You may also just extend the devise session controller and override any action you want to.
class Abc < Devise::SessionsController
# this just reopens the class.
# Remember classes are never "closed" in ruby!
end
I like the ruby way of solving this, I guess that in your UsersController after a POST request the user will be returned and signed in using the sign_in(Object) helper Devise provides.
Also I suggest using a confirmed boolean instead of timestamp.
Why not check for the value using an if else statement the ruby way:
user.confirmed ? sign_in(user) : render :partial => 'path/partial'
Hope this might help you out

skip_filter in rails

I have a site with a coming soon page -- it's managed by a boolean value in the database and a method the application controller called by a before_filter.
def is_it_live?
#setting = Setting.find(1)
if #setting.is_it_live
return true
else
unless admin_signed_in?
redirect_to comingsoon_path
end
end
end
I tried to use skip_filter on the specific controllers that should be public if the site isn't live, specifically the one that's for comingsoon ... but it's not working. I'm getting a redirect when I go to the comingsoon path because it's still running the before_filter in the application controller. Anyway to fix this? Or a better way to handle the logic?
weird, did you try:
skip_before_filter :is_it_live, :only => [:action1, :action2]
Well, I solved the problem. I was also declaring is_it_live? as a helper method to use the logic in the views, so the problem might be that the filter was still getting called by the view (though it seems if the controller for the view is removing it from the filter chain, it should be removed the view, too? but maybe my thinking is just way off on that), taking it out fixed the problem.

Rails 3 - Routing to a user profile

Greetings all, newbie to Rails here. I'm currently having issues routing /profile to the current user's profile.
My route is as follows:
match "profile" => "users#show"
However, this is hitting me with the "Couldn't find User without an ID" error. I know it has to do with my show method in the Users Controller. That code is simply:
def show
#user = User.find(params[:id])
end
Now, I could add another method in my Users controller with "#user = current_user" and it works fine. However, it seems a bit redundant and would also require a copy of the show view page. From what I've gathered with Rails, it's all about keeping things neat and tidy.
I would appreciate it if someone could point me in the right direction. Thank you.
RailsGuides states:
Because you might want to use the same controller for a singular route (/account) and a plural route (/accounts/45), singular resources map to plural controllers.
So I think you want to change your code to be the following
def show
#user = !params[:id].nil? ? User.find(params[:id]) : current_user
end