Does around_action in ApplicationController::Base include before_action and after_action? I understand that around_action wraps around the specified action, but would like to know if it also wraps around the before, and after callbacks associated with that action.
For instance, let's look at a code modified from Rails documentation:
class ChangesController < ApplicationController
before_action :some_callback, only: show
around_action :wrap_in_transaction, only: :show
...
private
def wrap_in_transaction
yield unless true
end
end
Will some_callback ever be executed?
Yes, some_callback will be executed. These methods are completely unaware of one another, and will be performed in the order they are written.
It may interest you to see the code that rails uses to do this. You can find it at https://github.com/rails/rails/blob/cdaab2c479c819b04cc72a97c52b804832365cef/actionpack/lib/abstract_controller/callbacks.rb#L180. You will notice that they both call the _insert_callbacks method (https://github.com/rails/rails/blob/cdaab2c479c819b04cc72a97c52b804832365cef/actionpack/lib/abstract_controller/callbacks.rb#L87).
Also, why not just try it using console output or something? This type of thing should be very easy to verify with a quick trial (which is, I suspect, the reason behind this question's downvote).
Related
I've got several before filters similar to:
before_filter :setup_plan, except: :some_action, :another_action, :yet_another_action
But I have a 3 or 4 exceptions to many before filters. At first I was going to change the logic in all of my before_filter methods, but I found myself repeating a lot of code. In a more perfect world I would have a seperate controller for the actions I want to add, but I've got to add the actions in the same controller, and work around the structure that's already in place.
What I want to do is create a constant or variable with the methods I want to skip in my before filters, such as
ACTIONS_TO_SKIP = [:some_action, :another_action, :yet_another_action]
And then simply use before_filter :setup_plan, except: ACTIONS_TO_SKIP
I get an uninitialized constant error when doing this. I tried moving this to a method in a helper and also got an undefined method error.
I know I'm missing something, but can't figure it out. Is there really no way to pass an method or constant that returns an array of methods I want to skip in my before filters? Just trying to make my controller a little bit cleaner and less verbose.
You will need to declare the constant BEFORE the call to skip. The file is interpreted top down.
class FoosController
ACTIONS_TO_SKIP = [:yes, :this, :and, :something, :more]
before_filter :setup_plan, except: ACTIONS_TO_SKIP
end
Note that in recent Rails versions this is now called before_action:
Rails 4: before_filter vs. before_action
(perhaps you want to upgrade...)
You can try something like this:
before_filter :my_before_filter, if: :action_to_skip?
def action_to_skip?
%w[some_action another_action yet_another_action].member?(action_name)
end
Is there a simple way to append to the before_action list for a controller in rails, such that other before_action callbacks added later will run before and not after my callback?
My use is that I have a concern that other Controllers will include, and I want the controllers that include it to be able to add their own before_action methods but then have one of my methods called after all of those, but still before the actual action.
Since it's a pretty big codebase with a bunch of developers, for usability I don't want every user of this concern to have to do prepend_before_action or to have to remember to include my module after they declare their callbacks instead of at the top of the class.
I'm pretty sure there's no builtin way to do this, and I'm not super familiar with metaprogramming in ruby. But is there some way to hook into the internals of the callback list as the callbacks are running and add a new callback to the end or something?
I found a pretty simple solution - looking at the ActiveSupport::Callbacks source, I noticed that the CallbackChain#append_one method which is what is adding the before_action callbacks to the chain is calling a remove_duplicates method every time you add a callback. So I can do the following in my module, overwriting the before_action method:
module MyModule
extend ActiveSupport::Concern
included do
before_action :my_last_callback
end
class_methods do
def before_action(*args, &blk)
method(:before_action).super_method.call(*args, &blk)
method(:before_action).super_method.call(:my_last_callback)
end
end
def my_last_callback
# do stuff after all before_action callbacks
end
end
Now the child class can add as many before_action callbacks as they like, and they'll maintain their order but my_last_callback always gets called last. (There will now be extra insertions/deletions in the callback chain and now it's probably O(n^2) instead of O(n) in the number of callbacks, but I don't anticipate there ever being enough callbacks to make this an issue).
I would like to ask if i should keep the empty methods in my controller (Its a question about code style):
before_action :set_project, only: [:show,:new]
def show
end
def new
end
Should i keep it like this or simpy remove show and new action
class ProjectController < ApplicationController
before_action :set_project
def index
#indexaction
end
def create
#createaction
end
is it more Railish way? Rails Styleguide doesnt indicate any sollution to it, only that:
def show
end
is better than
def show; end
If you're not defining any data in those methods, you can remove them.
Rendering By Default:
Rails automatically infers the view from action names in routes.
If you're not defining data (only to be done in the controller), you'll can rely on the view being loaded without the action being present:
You've heard that Rails promotes "convention over configuration". Default rendering is an excellent example of this. By default, controllers in Rails automatically render views with names that correspond to valid routes. For example, if you have this code in your BooksController class:
class BooksController < ApplicationController
end
And the following in your routes file:
resources :books
And you have a view file app/views/books/index.html.erb:
<h1>Books are coming soon!</h1>
Rails will automatically render app/views/books/index.html.erb when you navigate to /books and you will see "Books are coming soon!" on your screen.
Good ref: Rails doesn't need index method in controller defined?
If you want to use those methods in future, keep those methods, else remove them. There will not be any problem even if they are kept.
Also remove the routes to those methods if they are created and you dont want to use them. Code should be as simple as it can.
If it's truly about style first keep your comments above, so that if you ever run rdoc or generate docs, they take whatever comments come before the def show and use that to build out the paragraph describing what this method "does".
Example
class ProjectController < ApplicationController
before_action :set_project
#indexaction is awesome and will be used to do stuff like look at all the projects
def index
end
# will hopefully create your project
def create
end
Yeah but don't keep it if it isn't used...
If routes aren't used, don't have them lying around. By default you get things like blah.com/projects/1.json and if you haven't locked this down (or even if you have and a user is inside the app) they could easily get the json result, assuming you left everything there for later. Let alone if you have a before_filter that does 'stuff' to projects on load`.
commit it once into git and then delete it and commit again. If you ever need to reinstate it, at least github/bitbucket history or git history if you are sadistic, will have it to copy and paste.
Just a thought in my mind. what is the difference the following
before_filter
class ApplicationController < ActionController::Base
before_filter :foo
def foo
#mode = Model.new
end
end
ruby initialize
class ApplicationController < ActionController::Base
def initialize
foo
end
def foo
#mode = Model.new
end
end
Does ruby's initialize method work as expected in rails?
If yes, then can we use initialize in place a filter has to be applied to all actions in a controller?
For each request, you do get a fresh instance of ApplicationController, but the big no-no here is that you're attempting to override core behavior of ActionController::Base#initialize without calling the parent behavior.
ApplicationController < ActionController::Base
def initialize
super # this calls ActionController::Base initialize
init_foo
end
private
def init_foo
#foo = Foo.new
end
end
This is not idiomatic Rails behavior though. They give you before_filter for a reason; so use it.
I believe this was covered in Practical Object-Oriented Design in Ruby by Sandi Metz.
Suppose you are designing a base class for other developers/users, and want to allow them to hook into various steps in a procedure (e.g. initialization.) In general, there are two ways:
Break up the procedure into small methods, and (in the documentation) remind users to use super whenever they override a method.
Include calls to various empty hook methods that users can override with custom functionality.
(I believe that these are variations of the Template Method pattern.)
The second way requires more effort on your part and less effort for your users.
In this specific case, before_filter provides a cleaner way to attach multiple hooks and encourages you to break up hooks into single-responsibility methods with meaningful names. This becomes more important in applications that use more controller inheritance.
I'm new to Ruby and working through some tutorials/screencasts. I've reached the section where they're discusisng the before_filter callback, and it's using some syntax that's a little weird for me. I don't know if it's a feature of ruby, of if it's some rails magic, and was hoping someone here could set me straight or point me in the right direction w/r/t the manual
This is a code fragment from the screencast I'm watching
class MachinesController < ApplicationController
#...
before_filter :login_required, :only => [:report]
#...
def index
#etc...
end
def login_required
#etc...
end
end
In the context of rails, I understand that before_filter is a callback that will fire login_required method when the report action is called. However, it's not clear to me what it is within the context of ruby. In other languages classes typically contain methods, properties, class variables and constants defined within the braces.
However, this looks like its a function call inside the class, and some experiments have show that you can put code in your class definitions and have it called when the program runs. Is this correct? If so, are there special contextual rules for code that's put inline into a class like that? (i.e. would the before_filter function in rails know what class it was called from) If not, what magic is rails doing here?
before_filter is a not actually a callback. It's a class method of ActiveRecord::Base that sets up a callback when you call it. So in this example:
before_filter :login_required, :only => [:report]
When the class is loaded, the method is called, and it adds :login_required to the filter chain for the report method.
The convention for these types of calls is to drop parens, but it would work just fine (and would be more easily identifiable as a method call) if you did this:
before_filter(:login_required, :only => [:report])
Unlike in some other languages, in Ruby the class can be modified at runtime and you can make function calls from within the class definition. So what's happening in this case is that you are calling the before_filter function, which then modifies the MachinesController class definition at runtime.
This is the mechanism which allows for the strikingly beautiful (to my eyes, at least) syntax that you get with Rails where it almost looks like you're using some sort of Domain Specific Language to describe your models. Stuff like the validates, has_many and belongs_to function calls on model classes.
My understanding is that this is called a macro and falls under the umbrella of meta programming. You can read more about this topic.
Ruby is so cool. You can definitely send messages from within a class block. As I understand it, what things like class do, other than the obvious, is control the identity of self. Thus, you should be able to call any method of the class or included modules from there.
I'm not sure exactly what your question is, but here's my interpretation:
before_filter
This is a class method call see ActionController
:login_required
This is a parameter to the before_filter method, and used as a callback using Object#send
:only => [:report]
This is an additional Hash parameter to before_filter see ActionController again.
I'd also suggest looking at the implementation of the before_filter method for insight.