Apoligies if this is a noob question, but I am new and have a question about initializing and using instance variables in ruby on rails. I can create an instance variable like this in a model:
class MyClass
def do_stuff
#object_to_be_reused = []
#make a DB call here populating the array with a bunch of objects
end
end
And while I'm there on that page using that class, #object_to_be_reused works great as I only have to make a db call to set it once. However...
When I switch pages and come back later, #object_to_be_reused is still set to it's previous value. How do I re-initialize #object_to_be_reused such that, it is always not present when loading the page?
Thanks!
If you want to reset a variable each time an action is performed (or for selected actions only) I recommend you creating a before_action / before_filter in the controllers and do it:
before_action :reset_my_class_variable, only: [:show, :edit] #applies to actions
before_filter :reset_my_class_variable #applies wide
#code
private
def reset_my_class_variable
Myclass.do_stuff
end
Related
I'm learning alot about the DRY concept in Rails so here's my question:
I have a fixed sidebar in my application that always needs to load various Objects, such as Locations.
In the controller related to my index page, actually in controllers/pages_controller.rb I'm loading #locations:
#company = current_user.company
#locations = if #company
current_user.company.locations.order(:name)
else
[]
end
Which works fine for my navigation menu (sidebar), however, once I select a location and load a view delegated from a different controller (in this case locations/show.html.erb) my #locations variable is no longer found.
Sure, I could add it to the show method in my locations_controller.rb file, but that isn't very DRY considering I'd have to put the above code in every single controller method that relies on the sidebar navigation menu (all of them!) since it's fixed.
What's the DRY way to do this once and not have to do it in every controller?
You can create a method in your application_controller
def set_locations
....
end
Then in your pages_controller and locations_controller add a before_filter
before_filter :set_locations
It will set call set location before all all methods of the pages and locations controller.
If you want to set locations only for few controller actions then call:
before_filter :set_locations,:only=>[:show,:index, :your_action_name]
Updated:
In Rails 5 before_filter is deprecated and you can use before_action
You could add it to the ApplicationController in a method that runs before every action, every controller inherits from this ApplicationController so it will be available.
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.
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).
is there any way to persist (preserve) parameters in Rails controller? It should be passed to every action, then to every view and every link.
Example situation:
I have entity A with its controller. Besides, I have another entity B which is dependent on A. I need to access the "parent" A entity very often, so I'd like to have it still as
http://some_url/b_controller/b_action?a_entity=xyz
You should be able to do everything from your controller, using a combination of before_filter and default_url_options :
class MyController < ApplicationController
before_filter :set_a_entity
def set_a_entity
#a_entity = params['a_entity']
# or #a_entity = Entity.find(params['a_entity'])
end
# Rails 3
def url_options
{:a_entity => #a_entity}.merge(super)
end
# Rails 2
def default_url_options
{:a_entity => #entity}
end
end
This doesn't solve the problem of setting the initial value of #a_entity, but this can be done from anywhere (view, controller, etc).
If you want this parameter passed around in multiple controllers, you can replace MyController < ApplicationController with ApplicationController < ActionController::Base and it should work as well.
Hope this helps.
why not put it in a session parameter then?
session["a_entity"] = "xyz"
that way you can access it in all your other controllers too until you clear it or it expires.
more info here:
http://api.rubyonrails.org/classes/ActionController/Base.html
I would like to add a couple of instance variables to my controller, since the variables in question are required from within more than one action's view. However, the below example does not work as I would expect.
class ExampleController < ApplicationController
#var1 = "Cheese"
#var2 = "Tomato"
def show_pizza_topping
# What I want is the above instance vars from within the view here
end
def show_sandwich_filling
# What I want is the above instance vars from within the view here
end
end
As I understand it, Rails takes the instance variables from the controller and makes them available in the view. If I assign the same variables within the action methods, it works fine - but I don't want to do it twice. Why does my way not work?
(Note: this is a bit of a rubbish example, but I hope it makes sense)
EDIT: I have found the answer to this question here: When do Ruby instance variables get set?
EDIT 2: when is the best time to use filters such as before_filter and the initialize method?
These types of things should be handled in a before_filter. A before filter, like the name implies, is a method that will get called before any actions, or only the ones you declare. An example:
class ExampleController < ApplicationController
before_filter :set_toppings
def show_pizza_topping
# What I want is the above instance vars from within the view here
end
def show_sandwich_filling
# What I want is the above instance vars from within the view here
end
protected
def set_toppings
#var1 = "Cheese"
#var2 = "Tomato"
end
end
Or, you could have your before_filter only work on one of your actions
before_filter :set_toppings, :only => [ :show_pizza_topping ]
Hope this helps.
EDIT: Here's some more information on filters in ActionController.
Those aren't instance variables, are they?
class A
#x = 5
def f
puts #x
end
end
A.new.f
=> nil
You're defining it at the class-level, not the instance-level. As "theIV" points out, you need to assign them inside an instance method.