inherited_resources and cancan conflict - ruby-on-rails

There are conflict with inherited_resources and Ryan Bates's cancan gem.
I have some simple controller
class IssuesController < InheritedResources::Base
respond_to :html
load_and_authorize_resource
def tag
#issues = Issue.tagged_with(params[:tag]).recent.paginate(:page => params[:page])
end
protected
def collection
#issues = end_of_association_chain.recent.paginate(:page => params[:page], :per_page => Settings.per_page_defaults.issues)
end
end
and route
resources :issues do
collection do
get "tag/:tag" => "issues#tag", :as => "tags"
end
end
Everything looks correct, but on attempt to request http://localhost:8080/issues/tag/tag1
i see
ActiveRecord::RecordNotFound in IssuesController#tag
Couldn't find Issue without an ID
After removing load_and_authorize_resource from controller - everything works fine, but i need access control.
Any idea how to solve this issue?

use load_and_authorize_resource :except => :tag. Note that this wont apply rules. If you need to apply some use authorize! instead.

Related

Expiration of controller action from Sweeper does not work

Having a controller handling rendering of large XML feeds
module Spree
class FeedsController < Spree::StoreController
...
caches_action :products_out
cache_sweeper FeedSweeper
# XML feed in format of `xxxxxxx.com'
def products_out
#products = Product.all
respond_to do |format|
format.xml
end
end
end
Bellow is the corresponding sweeper's sublass:
module Spree
class FeedSweeper< ActionController::Caching::Sweeper
observe Product
def after_update(product)
# cache_configured? is nil, #controller is nil here, why ?
expire_action(:controller => :feeds,
:action => :products_out,
:format => :xml)
end
end
Above Spree::FeedSweeper is called when Spree::Product gets updated, however it seems expire_action silently dies and cache won't get invalidated.
Can somebody explain the issue ? Even better suggest some solution ?
Thanks.
Which Rails version are you using? expire_action seems to be deprecated after Rails 3.2.14.
Maybe you can try to find out the key then directly clear it with Rails.cache.delete(key).

Trying to override controller in Thoughtbot's Clearance gem for Rails

I am using Clearance 1.1.0 gem with Ruby on Rails 4.0.1. I am trying to override the sessions controller to provide my own custom method. I have not been able to successfully get rails to use my controller.
/app/controllers/sessions_controller.rb
class SessionsController < Clearance::SessionsController
private
def flash_failure_after_create
flash.now[:notice] = translate(:bad_email_or_password,
:scope => [:clearance, :controllers, :sessions],
:default => t('flashes.failure_after_create', :new_password_path => new_password_path).html_safe)
end
end
I have tried a few different things inside my routes.rb file, and have been unsuccessful. I want to change the route sign_in.
get '/sign_in' => 'sessions#new', :as => 'sign_in'
Yields the following error.
You may have defined two routes with the same name using the :as
option, or you may be overriding a route already defined by a resource
with the same naming.
Any ideas? Thank you!
Edit: I made a mistake. I actually need sessions#create to use my controller. I'm trying to pass a different variable to the yaml file for the flash when the session login fails.
Edit 2: I the appropriate session#create line to to my routes. In my session controller, I copied and edited for testing the flash_failure_after_create method. It is not being called. So I then copy the create method over. Now, my create method is being called, but not my flash_failure_after_create method. To get it to be called, I had to have the create method copied from gem, and changed status.failure_message to directly call the flash_failure_after_create method. Is this some sort of bug with clearance?
routes.rb
post 'session' => 'sessions#create', :as => nil
sessions_controller.rb
class SessionsController < Clearance::SessionsController
def create
#user = authenticate(params)
sign_in(#user) do |status|
if status.success?
redirect_back_or url_after_create
else
#flash.now.notice = status.failure_message
flash.now.notice = flash_failure_after_create
render :template => 'sessions/new', :status => :unauthorized
end
end
end
private
def flash_failure_after_create
# Changed flash for easy testing
flash.now[:notice] = 'Ballz.'
#flash.now[:notice] = translate(:bad_email_or_password,
# :scope => [:clearance, :controllers, :sessions],
# :default => t('flashes.failure_after_create', :sign_up_path => sign_up_path).html_safe)
end
end
I believe this will work:
get '/sign_in' => 'sessions#new', :as => nil
Rails 4 no longer supports overriding route names, so don't name your override. The mapping is still the same so sign_in_path should still work.

Where do I put a rails method/scope that uses params?

I have a scope that uses RubyGeocoder method, near, to filter events by location using param[:searchCity]. The param gets the user's geolocation so it shows events only near them. I currently have it working in my events_controller index action, but I also need to call it on my home page.
Considering it's a filter that gets data from the database, I thought it would be best to go in the model, but I'm finding conflicting information on whether having a param in the model is ok or bad practice. Also, I can't get it to work in the model with the param present.
What's the best practice for something like this? Where should I place the scope, the model, controller, helper, or somewhere else?
Here's my code:
Model:
class Event < ActiveRecord::Base
# attr, validates, belongs_to etc here.
scope :is_near, self.near(params[:searchCity], 20, :units => :km, :order => :distance) #doesn't work with the param, works with a "string"
end
Controller:
def index
unless params[:searchCity].present?
params[:searchCity] = request.location.city
end
#events = Event.is_near
# below works in the controller, but I don't know how to call it on the home page
# #events = Event.near(params[:searchCity], 20, :units => :km, :order => :distance)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #events }
end
end
The line I'm calling in my home page that gets how many events are in the area
<%= events.is_near.size %>
Edit: Using a lambda seems to be working. Is there any reason I shouldn't do it this way?
Model:
class Event < ActiveRecord::Base
scope :is_near, lambda {|city| self.near(city, 20, :units => :km, :order => :distance)}
end
Controller:
def index
#events = Event.is_near(params[:searchCity])
...
home.html.erb
<%= events.is_near(params[:searchCity]).size %>
Accessing the params in model is not possible. Params is something which is made to exist only at controller and view level.
So best way is to write some helper method in controller to perform this.
Class Mycontroller < ApplicationController
before_action fetch_data, :only => [:index]
def fetch_data
#data = Model.find(params[:id])#use params to use fetch data from db
end
def index
end

routing issue rails 3.1 thums_up and forem

I am trying to integrate forem with thumbs_up. I have inherited the forem Post model and controller.
Here is my controller :-
class PostsController < Forem::PostsController
def vote_up
begin
current_user.vote_for(#post = Post.find(params[:id]))
render :nothing => true, :status => 200
rescue ActiveRecord::RecordInvalid
render :nothing => true, :status => 404
end
end
end
Here is how the Post Controller of Forem looks like :-
module Forem
class PostsController < Forem::ApplicationController
before_filter :authenticate_forem_user
before_filter :find_topic
.
.
.
.
private
def find_topic
#topic = Forem::Topic.find(params[:topic_id])
end
end
end
Here is my routes:-
mount Forem::Engine, :at => "/forums"
resources :posts do
member do
post :vote_up
end
end
Here is my view :-
<%= link_to t('vote for this post!', :scope =>"forem.post"), main_app.vote_up_post_path(#post), :method => :post %>
This is the error which I am getting :-
ActiveRecord::RecordNotFound in PostsController#vote_up
Couldn't find Forem::Topic without an ID
What could be the issue?
Your problem is the before filter:
module Forem
class PostsController < Forem::ApplicationController
#...
before_filter :find_topic
#...
def find_topic
#topic = Forem::Topic.find(params[:topic_id])
end
and then:
class PostsController < Forem::PostsController
def vote_up
#...
So find_topic will be called before vote_up but the route for vote_up won't have a :topic_id; no :topic_id means that find_topic will be doing this:
#topic = Forem::Topic.find(nil)
and that's where your error comes from.
Three options come to mind:
Move vote_up to a separate controller class that doesn't inherit from Forem::ApplicationController.
Add a skip_filter :find_topic, :only => :vote_up to PostsController.
Adjust the route and link to get a :topic_id in the route.
If upvoting doesn't need the #topic then (1) or (2) would work, otherwise you'll have to go with (3).
check rake routesin command prompt,
and check id should be post :vote_up OR get:vote_up – ror_master
and use debugger in controller!
and write params there perhaps you will get solution.

Rails 3 - CanCan -Defining a Permission for Create

I have the following in my controller for Attachment
def upload
#attachment = Attachment.build(:swf_uploaded_data => params[:attachment][:attachment], :user_id => current_user.id, :project_id => params[:space_id])
....
end
What I'd like from CanCan is to only allow users to upload to a project_id they belong to. I confirmed the controller is getting the correct info, no nils
Here is my cancan:
can :upload, Attachment do |attachment|
Rails.logger.info 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX- include CanCan::Ability - ATTACHMENT'
Rails.logger.info attachment.inspect
Rails.logger.info attachment.project
current_user.try(:role, attachment.space)
end
Problem here, is that attachment. is nil, and attachment.project is nil? How do you solve for this issue with CanCan so I can make sure only project teammembers can upload attachments to the project?
Thank you
I think the best approach it to do it at a lower level with the authorize! method that the Controller action.
So ...
#AttachmentController
#Will remove it from cancan
load_and_authorize_resource :except => [:upload]
def upload
#attachment = Attachment.build(:swf_uploaded_data => params[:attachment][:attachment], :user_id => current_user.id, :project_id => params[:space_id])
#add the authorize logic explicitly here when you have the attachment model populated
authorize! :upload, #attachment
end
Let me know if that works for you.
For example if you want to allow create events for current loop only:
You use in the view
link.... if can? :create, #loop.events.new
and then in controller
skip_authorize_resource only: [:new, :create]
...
def new
#event.loop_id = #loop.id
authorize! :create, #event
end
#similar for create action

Resources