before_filter with parameters

44,095

Solution 1

I'd do it like this:

before_filter { |c| c.authenticate_rights correct_id_here }

def authenticate_rights(project_id)
  project = Project.find(project_id)
  redirect_to signin_path unless project.hidden
end

Where correct_id_here is the relevant id to access a Project.

Solution 2

With some syntactic sugar:

before_filter -> { find_campaign params[:id] }, only: [:show, :edit, :update, :destroy]

Or if you decide to get even more fancy:

before_filter ->(param=params[:id]) { find_campaign param }, only: %i|show edit update destroy|

And since Rails 4 before_action, a synonym to before_filter, was introduced, so it can be written as:

before_action ->(param=params[:id]) { find_campaign param }, only: %i|show edit update destroy|

NB

-> stands for lambda, called lambda literal, introduce in Ruby 1.9

%i will create an array of symbols

Solution 3

To continue @alex' answer, if you want to :except or :only some methods, here is the syntax:

before_filter :only => [:edit, :update, :destroy] do |c| c.authenticate_rights params[:id] end 

Found here.

Solution 4

I find the block method using curly braces instead of do...end to be the clearest option

before_action(only: [:show]) { authenticate_rights(id) }

before_action is just the newer preferred syntax for before_filter

Share:
44,095

Related videos on Youtube

choise
Author by

choise

Updated on May 18, 2020

Comments

  • choise
    choise almost 4 years

    I have a method that does something like this:

    before_filter :authenticate_rights, :only => [:show]
    
    def authenticate_rights
      project = Project.find(params[:id])
      redirect_to signin_path unless project.hidden
    end
    

    I also want to use this method in some other Controllers, so i copied the method to a helper that is included in the application_controller.

    the problem is, that in some controllers, the id for the project isn't the :id symbol but f.e. :project_id (and also a :id is present (for another model)

    How would you solve this problem? is there an option to add a parameter to the before_filter action (to pass the right param)?

  • choise
    choise about 13 years
    the problem is, sometimes both are present (nested) and it finds a project that isn't the right one.
  • choise
    choise about 13 years
    is there a way to add a ,:only => [:show] symbol? i'm getting an error trying before_filter { |c| c.authenticate_rights correct_id_here }, :only => [:show]
  • fguillen
    fguillen over 12 years
    Try the other way around: before_filter(:only => [:show]) { <block_code_here> }. More examples here: apidock.com/rails/ActionController/Filters/ClassMethods/…
  • Richard Michael
    Richard Michael about 12 years
    If you secure this by making the before_filter a private method, then perhaps re-factor (e.g. move it to a parent controller, ApplicationController, etc.), you'll need to use c.send(:filter_name, ...) as the filter will not run in the controller context. guides.rubyonrails.org/…
  • oreoshake
    oreoshake about 11 years
    Doing this makes it so the before_filter cannot be overridden/skipped due to it's lack of a name (proc). The values I want to pass in are class level. Is that possible?
  • Ola Tuvesson
    Ola Tuvesson about 11 years
    @choise: That should not happen: if project_id is present the or clause will ensure this is used - only if a project_id is not supplied will the id param be selected. In other words: when both parameters are supplied, the or clause ensures the correct value is used, as it will always prefer project_id. Naturally, you would not want to call this method when neither is present, or when there is no project_id but there is an id which does not reference a project.
  • marcus3006
    marcus3006 over 10 years
    @oreoshake: i have the same problem. Did you found a solution?
  • Augustin Riedinger
    Augustin Riedinger over 10 years
    How can I do this with a :only or a :except rule, like before_filter { |c| c.authenticate_admin! params[:id] }, :only => [:edit, :update, :destroy] ?
  • David Pelaez
    David Pelaez about 10 years
    This answer is more elegant because the lambda defaults to the execution context of the class, hence private methods can be called without using '.send'
  • David Pelaez
    David Pelaez about 10 years
    The fact that passing the block requires using send means it's better to use a lambda as suggested in the answer of @vadym-tyemirov
  • ahnbizcad
    ahnbizcad over 9 years
    @Vadym Tyemirov Is find_campaign the private method name? In param=params[:id], is param the name of the new local variable that will be passed as an argument to find_campaign? Meaning, that within the find_campaign private method itself, we use param not, params{:id]?
  • Vadym Tyemirov
    Vadym Tyemirov over 9 years
    find_campaign could be either, but I'd make it private to be sure we don't expose what is not consumed. params is a hash variable available to our methods, param is any variable that you'd need to pass to find_campaign method, e.g. before_action ->(campaign_id=params[:id]) { find_campaign(campaign_id) }, only: %i| show edit update destroy |
  • ahnbizcad
    ahnbizcad about 9 years
    FYI to beginners: c in this case is the controller, and you're calling an instance method you define in this controller.

Related