before_action extend from superclass - ruby-on-rails

I have next definitions:
ApplicationController:
before_action :set_resource, only: [:edit, :update, :destroy]
...
private
def set_resource
...
OtherController < ApplicationController
before_action :set_resource, only: [:new_action1, :new_action2]
...
def new_action1
....
def new_action2
I expect set_resource method will be called before actions edit, update, destroy, new_action1, new_action2, but it right only for methods: edit, update, destroy

I faced almost the same problem today while writing plugin for Redmine.
There is an issues_controller with callbacks in Redmine:
OtherController < ApplicationController
before_filter :find_issue, :only => [:show, :edit, :update]
before_filter :authorize, :except => [:index]
end
And I added another action in module that is being included in issues_controller:
module IssuesControllerPatch
def self.included(base)
before_filter :find_issue, :only => [:show, :edit, :update, :merge]
end
end
What happened here is newly added filter for merge action gets called after authorize method, thus failing authorization.
To solve the problem, I overrode authorize method like that:
module IssuesControllerPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
alias_method :default_authorize, :authorize
alias_method :authorize, :authorize_with_merge
end
end
module InstanceMethods
def authorize_with_merge
find_issue if params[:action] == "merge" && params[:controller] == "issues"
default_authorize
end
end
end
Not quite elegant, but works like a charm. This should help you, as well.

Related

What is the difference between before_action and prepend_before_action in Rails?

My codebase contains callbacks like
prepend_before_action :authenticate_api_user! and
before_action :authenticate_api_v1_user!
What is the difference between these two?
Generally before_action runs before every action to a method and
prepend_before_action does what it says. It just add your definition at index zero.
Here is a great use case to prove the same:
class ConfuseUsersController < ApplicationController
prepend_before_action :find_user, only: [:update]
prepend_before_action :new_user, only: [:create]
before_action :save_and_render
def update
end
def create
end
private
def find_user
#user = User.find(params[:id])
end
def new_user
#user = User.new
end
def save_and_render
persited = #user.persited?
#user.assign_attributes(user_params)
if #user.save
redirect users_path(#user)
else
render (persited ? :edit : :new)
end
end
end
before_action :save_and_render this makes save_and_render to get called before every action.
prepend_before_action :find_user, only: [:update] This prepends find_user function to get called before save_and_render
Another example:
We have an ApplicationController where...
class ApplicationController < ActionController::Base
before_action :one
before_action :three
end
Now in any controller if we want to execute any other method for e.g. two before three you can use prepend_before_action like
prepend_before_action :three, :two
class AdminsController < ApplicationController
prepend_before_action :three, :two
end
Now before three gets executed two will get execute and then three for this specific method.

How to push actions to already defined before_filter?

I am writing a redmine plugin and need to add some actions to before_filter that is already defined in redmine's 'IssuesController'
For example,
issues_controller.rb
class IssuesController < ApplicationController
before_filter :find_issue, :only => [:show, :edit, :update]
before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
before_filter :find_project, :only => [:new, :create, :update_form]
before_filter :authorize, :except => [:index]
end
I want to add more actions to filters find_issue and find_project
So, in my plugin i'm gonna write a module and include it in IssuesController
issues_controller_patch.rb
module IssuesControllerPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
before_filter :find_issue, :only => [:new_action1, :new_action2]
before_filter :find_project, :only => [:new_action1, :new_action2]
#prepend_before_filter :find_issue, :only => [:new_action1, :new_action2]
#prepend_before_filter :find_project, :only => [:new_action1, :new_action2]
end
end
module InstanceMethods
end
end
unless IssuesController.included_modules.include?(IssuesControllerPatch)
IssuesController.send(:include, IssuesControllerPatch)
end
This is not working for me, because it's putting it on the bottom of filters chain and authorize action is executed and authorization is because authorization depends on project.
I also tried to use prepend_before_filter and it's also not working because it's putting it on the top of filters chain, even before the user loads from session.
So, how can I update action list for filters defined in IssuesController?
Rails 3.2, Ruby 1.9.3, Redmine 2.6

Model level method to call in before_filter

I am working in rails 2, I have a model level method, which i want to call in before_filter. How can i do this?
I tried this way, but its not working
before_filter :LmsUser.can_edit_update, :only => [:new, :create, :edit, :update, :destroy]
You should add a method to your controller and use that as the before filter. For example:
class MyController < ApplicationController
before_filter :check_permissions,
:only => [:new, :create, :edit, :update, :destroy]
private
def check_permissions
unless LmsUser.can_edit_update
# redirect_to, render, or raise
end
end
end
See the filters section of the Action Controller Overview guide for more information.

Cannot expire cached fragment by default methods in Ruby on Rails + Devise

I'm using Devise as authenticating solution in Rails and I have a cached fragment :recent_users.
I want this fragment to expire when a new user is registered, changed or removed, so I put in my(manually created) users_controller.rb
class UsersController < ApplicationController
cache_sweeper :user_sweeper, :only => [:create, :update, :destroy]
...
But my fragment does not expire when new creates or changes.
My user_sweeper contains basic prescriptions
class UserSweeper < ActionController::Caching::Sweeper
observe User
def after_save(user)
expire_cache(user)
end
def after_destroy(user)
expire_cache(user)
end
private
def expire_cache(user)
expire_fragment :recent_users
end
end
What am I doing wrong?
Problem solved!
I followed this steps and everything works:
$ mkdir app/controllers/users
$ touch app/controllers/users/registrations_controller.rb
In registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
cache_sweeper :user_sweeper, :only => [:create, :update, :destroy]
end
Problem was that Registrations in Devise is a separate controller.
Put this in applications_controller.rb
class ApplicationController < ActionController::Base
cache_sweeper :user_sweeper, :only => [:create, :update, :destroy]
...

Rails: Before process_action callback :authenticate_user! has not been defined

I'm creating a rails app that includes devise.
I'm trying to add Twilio messaging to my site with Ngrok, i used this tutorial:
https://www.twilio.com/blog/2016/04/receive-and-reply-to-sms-in-rails.html
I was able to open Ngrok in the console and get the web-id they give for my url.
I keep getting this error when I plug the url into my browser ..I'm supposed to get to my own rails local app. Not sure whats wrong.
What I added in my messaging controller made for ngrok:
class MessagesController < ApplicationController
skip_before_filter :verify_authenticity_token
skip_before_filter :authenticate_user!, :only => "reply"
def reply
message_body = params["Body"]
from_number = params["From"]
boot_twilio
sms = #client.messages.create(
from: Rails.application.secrets.twilio_number,
to: from_number,
body: "Hello there, thanks for texting me. Your number is #{from_number}."
)
#twilio expects a HTTP response to this request
end
private
def boot_twilio
account_sid = Rails.application.secrets.twilio_sid
auth_token = Rails.application.secrets.twilio_token
#client = Twilio::REST::Client.new account_sid, auth_token
end
end
really unsure what is wrong.
when its not connecting to the 'def reply' and authenticate_user should be defined by devise.
Twilio developer evangelist here.
It looks like this was a problem that Rails 5 seems to have introduced. If the filter hasn't been defined by the time it is used in a controller it will raise an error. This was discovered in the Clearance project too.
Their fix was to pass the raise: false option to skip_before_filter:
class MessagesController < ApplicationController
skip_before_filter :verify_authenticity_token
skip_before_filter :authenticate_user!, :only => "reply", :raise => false
end
I had a similar issue to this when I was working on a Rails 6 application with Devise gem for authentication and authorization.
I added a skip_before_action :authenticate_admin!, only: [:index, :show] to the Products controller
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
skip_before_action :authenticate_admin!, only: [:index, :show]
def index
#products = Product.all
end
.
.
.
end
And it was throwing the error below when I visit the Products page:
Before process_action callback :authenticate_admin! has not been defined
Here's how I fixed it:
To use the skip_before_action :authenticate_admin!, only: [:index, :show] in the Products controller, I first needed to define the before_action :authenticate_user! in the application_controller:
# app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_admin!
end
Now I can use the skip_before_action :authenticate_admin!, only: [:index, :show] in the Products controller:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
skip_before_action :authenticate_admin!, only: [:index, :show]
def index
#products = Product.all
end
.
.
.
end
An alternative, if I don't want to define the before_action :authenticate_user! in the application_controller is to use the before_action :authenticate_admin!, except: [:index, :show]:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
before_action :authenticate_admin!, except: [:index, :show]
def index
#products = Product.all
end
.
.
.
end
That's all.
I hope this helps

Resources