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
Sending Http Post Request in Ruby by Net::Http
How to Refer a Local Gem in Ruby
Why Do I Need Asterisk Before an Array
Using Rest-Client to Download a File to Disk Without Loading It All in Memory First
Combine Thumbnails to One Large Image with Rmagick
Using %I and %I Symbol Array Literal
Port in Use When Not Using a Port
How to Get The Page Source with Mechanize/Nokogiri
How to Restart Rails from Within Rails
Ruby on Rails Looks for CSS in Assets Instead of Public/Stylesheets
Re-Opened Nested Module Anomaly in Ruby
When Trying to Generate a Model with Rails and Postgresql, the Command Hangs Without Error
Ruby on Rails: Two References with Different Name to the Same Model
Text_Field_With_Auto_Complete Inside Form_For
Ror, Can't Iterate from Datetime/Timewithzone
Access Localhost on MAC from Xcode? Phonegap Communicating with Ajax to a Local Rails App