How to Do a Before_Action in Ruby (Like in Rails)

Is it possible to do a before_action in Ruby (like in Rails)?

What you are looking for is Aspect oriented programming support for ruby. There are several gems implementing this, like aquarium.

I think though, that in your case, some lazy checks will be sufficient:

class Calculator
def numbers
raise Exception, "calculator is empty" if @numbers.nil?
@numbers
end

def push number
@numbers ||= []
@numbers << number
end

def plus
numbers.inject(:+) # <-- will throw the correct Exception if `@numbers` is nil
# ...
end

def minus
# ...
end

def divide
# ...
end

def times
# ...
end

# ...
end

How does only: at before_action work in Rails?

The only option of before_action defines one action OR a list of actions when the method/block will be executed first.

Ex:

# defined actions: [:show, :edit, :update, :destroy]
before_action :set_newsletter_email, only: [:show, :edit]

The set_newsletter_email method will be called just before the show and edit actions.


The opposite option except define when NOT to execute the method/block.

# defined actions: [:show, :edit, :update, :destroy]
before_action :set_newsletter_email, except: [:show, :edit]

The set_newsletter_email method will be called for all existing actions EXCEPT show and edit.


only / except is just a kind of whitelist/blacklist.

How to use before_action with :unless and params

  before_action do |controller|
unless params[:user_id].to_i == current_user.id
controller.authorize
end
end

Alternatively you can do so like:-

before_action :authorize

def authorize
unless params[:user_id].to_i == current_user.id
#do your stuff..
end
end

2nd Alternative

before_action :authorize, unless: -> { params[:user_id].to_i == current_user.id }

Set a before action to all member routes?

The show, edit, update, destroy actions are precisely all member actions. They are the only ones that require to find the model.

If you have your own member action, then you'll have to add it to the list yourself.

before_action :set_item, only: [:edit, ..., :my_member_action]

Or, you can use the :except option to exclude all the collection actions that do not need it:

before_action :set_item, except: [:index, :create]

This way, if you add other member actions, you wont have to change anything.
Personally, I prefer to be explicit and use :only.

I'm pretty sure there is no easier way to do it, you can't detect all member actions automatically.


edit:

I really don't think you should do that but...

You can access the name of your controller with the controller_name method.

Getting the routes related to the controller:

routes = Rails.application.routes.routes.select { |r| r.defaults[:controller] == controller_name }

Then, I think the best way to see if a route is a member route is that the @parts array includes :id. Maybe you can find a more robust way.

So I would do:

routes.select { |r| r.parts.include?(:id) }.map { |r| r.defaults[:action] }.map &:to_sym

That would give you: [:show, :preview, :my_challenges] for

 resources :users, only: [:index, :show], controller: 'accounts/users' do
member do
get :preview
get :my_challenges
end
end

class ApplicationController < ActionController::Base 

def member_routes
Rails.application.routes.routes
.select { |r| r.defaults[:controller] == controller_name && r.parts.include?(:id) }
.map { |r| r.defaults[:action] }
.map(&:to_sym)
end

end

class UsersController < ApplicationController
before_action set_model, only: member_routes
end

Rails: does before action in module overwrite the one in the class?

Rails is OSS.

Here is the implementation of skip_before_action.

Callbacks are implemented as a collection.

Unless prepend: true option is explicitly passed, newly defined callbacks are appended to the list of existing callbacks. That said, both would take place.

Also, self#included callback is called as it’s found in the source code, hence module one is appended to the class one.

How to determine the caller of a before_action

Do you think that a caller of a before_action is that action? This is not so. But, perhaps, you do need to find the caller. In this case, use caller. It'll return you a stack trace, which you can filter as you wish.

To find the action, use params[:action].



Related Topics



Leave a reply



Submit