User Story:
Action for Facebook that has open graph object.
For this I need to modify the tag defined in application.html
Problem:
The logic would need to be defined in helpers or the application_controller
From my understanding this is not clean.
Question:
I want to pass variables directly into the application.html view.
Preferably pass those variables from a custom controller into the application.html. This way I can still utilize the rails routing system to only pass those variables when I am on the facebook action.
The common mechanism for passing variables in to the view is to create instance variables in your controller as these are ported over automatically.
This is the standard approach if it is almost certain they will be used. For things that may not be used, create a helper method that will take care of providing them.
This is the difference between doing this:
def show
#facebook_graph = ...
end
And this in a helper:
def facebook_graph
...
end
Related
Suppose I have a controller with an index action and I would like to pass some data into the action's view (index.html.erb).
Typically, the rails way is to do: #some_var = some_value.
Does the above add to the global scope in a sense that #some_var is now available everywhere (helpers, etc...)? If so, is it better to do something like locals: {some_var: some_value} instead?
What are the tradeoffs if any?
Yes, #some_var is "global" in the sense that it added to the view context that is shared by views and helpers. So your controller, view, partials, and helpers can all access the same #some_var.
Using instance variables like this is the Rails convention: they just appear "like magic" in your views and helpers with no additional code. For simplicity, I would recommend it for most projects, especially as you are starting out.
However as your Rails app grows, here are some other best practices to keep in mind:
Try to limit your controller to assigning only one instance variable. If you find yourself assigning many instance variables in a single controller action, that is usually a sign that your controller is trying to do too much.
Avoid using instance variables in helpers. This makes your helper methods harder to reuse in other contexts, because they depend on instance variables being set "just right" by the controller. This can be a source of bugs.
Yes, I think you've got it. I prefer local arguments like that too, even though you're right Rails suggests you use instance variables.
I think instance variables may be okay when they are in a full template (never in a partial), and especially when you only have one of them that has the same name as the controller or whatever.
But in general, I agree with you. There is no downside to doing it with locals, unless you consider it confusing code, perhaps it would confuse someone who expects it to be the 'ordinary' Rails way.
I guess someone could argue that Rails templates are inherently tightly coupled to the controller, are meant to be that way, so it's no big deal to use instance variables -- the main negative of which is that it tightly couples your template to a particular controller implementation, but, they'd say, that's fine. I guess that's an opinion, apparently it is Rails' opinion! Certainly plenty of apps are written that way, and it's fine.
But there isn't really anything that's going to get in your way from going against the typical Rails way of doing things, and using local template arguments instead of instance variables. It works fine. I've done it.
I think you are right to be willing to question Rails -- sometimes Rails has made some odd choices. And also right to be cautious about going ahead doing something differently than Rails seems to wants you to, sometimes it does cause problems. In this case, I don't expect it will.
Nope, if you add #some_var = some_value to the index action then it will only be applied to that action. If you want to create a global action then you can apply it to the application.rb.
I highly recommend reading http://guides.rubyonrails.org/action_controller_overview.html
but something that might interest you in specific is this:
4.4 default_url_options You can set global default parameters for URL generation by defining a method called default_url_options in your
controller. Such a method must return a hash with the desired
defaults, whose keys must be symbols:
class ApplicationController < ActionController::Base def
default_url_options
{ locale: I18n.locale }
end end
These options will be used as a starting point when generating URLs,
so it's possible they'll be overridden by the options passed in
url_for calls.
If you define default_url_options in ApplicationController, as in the
example above, it would be used for all URL generation. The method can
also be defined in one specific controller, in which case it only
affects URLs generated there.
I am reading the RailsTutorial and it is like this:
in the routes.rb file we have added:
resources :users
Then in the app/views/users/show.html.erb file we are using #user
Then in app/controllers/users_controller.rb we can still use #user
Then in app/views/users/show.html.erb again we can use #user
So aren't these all in different folders and classes? so #user is public? how do they see and work together? because I don't have a deep knowledge of Rails this all looks like magic to me. If someone could shed some light on internals of what's going on would be great.
The users in your question are not all the same:
in routes.rb, users is not the #users / #user variable, but a symbol named :users. It could be anything else, :something, :anything, etc. It just a parameter to the "resources" method, which creates routes based on the name passed to it. So if you write, "resources :whatever", then rails will generate default routes for a class named WhateverController - if that exist, it will work
show.html is a view. It may use any member variable declared in it's controller / action (which is users_controller). But it is not global, if you have two controller, they can only use their own variables. Even more, two different actions (methods) in one controller can't use each other's variables, since they are not declared at that time.
in users_controller.rb you actually declare the #users variable which is used in the view
A request first touches your routes.rb file which will direct the request to the appropriate controller action.
ex. example.com/users/new will go to the UsersController new action
The new action will define instance variables which you can then access in your corresponding view (the new.html.erb in your user folder).
resource :users is a rails shortcut to create CRUD routing (http://guides.rubyonrails.org/routing.html#resources-on-the-web)
Each controller action is most likely going to have a different assignment for the #user instance variable. Read this example, http://www.tutorialspoint.com/ruby-on-rails/rails-controllers.html
More Good Reading:
http://www.devarticles.com/c/a/Ruby-on-Rails/Rails-Action-Controller/1/
the # signifies an instance variable. The scope of a variable defines where and how it can be accessed. It would be best for you to learn about variables and their various types in general. Check this out: http://ruby.runpaint.org/variables.
I need to call a method defined in a helper which uses content_for, I need to render some buttons& links at lots of views.
The question is, how can I benefit from the before_filter ? I know its not designed for helpers, so, what's the proper way to do so ?
Currently, I am calling the helper method at most of views, which seems not practical.
A before_filter will not be of any help here. A before_filter is used inside the controller, to execute method before starting an action. Generally, what one does:
verify authentications/access/authorisations
retrieve data
it can also be used to refactor code that is shared between controller methods
In your case, what I would consider are:
using a partial, to share the common view-part
use different layout, instead of application.html.erb to group the shared views together
push the shared view-part to application.html.erb
Hope this helps.
If you're calling a method in a bunch of views, you probably want to put it in the application layout (by default app/views/layouts/application.html.erb)
I am using Ruby on Rails 3 and I was advised (#user is a global variable, you can't 'localize' it. I would suggest passing local variables from your controller in the same way.) to use variables like user instead of #user in view files. Why to do that, exactly?.
So, I am considering pass from using #user to using user. That is, (in html.erb file) from using
#user.name
to using
user.name
At this time, for example, in the show method of my controller I have:
def show
#user = Users.find(1)
...
end
What I have to change in the controller to do that works in views?
This is only something you need to worry about when the same partial is called in the views from more than one controller.
Having a partial that is using #user in it (likely set in a users_controller), means that the moment you call that partial in a view from some other controller (for example; accounts_controller) that does not set #users you will get an error. If you reference only local variables in your partial you can set them as needed from any controller with the :locals hash that was described.
That's non sense, only instance_variables are sent from the controller to the view.
Nikita Rybak was not wrong in his answer, he just passed the instance variable contained in his view (#current_user) to a partial where it has a different name (user):
:locals => { :user => #current_user }
he concluded very well:
Local variables are local, so you don't need # to refer them.
Indeed you have two choices when working with a partial:
assume it has access to the instance variable (which is not advised)
pass the instance variable to the partial with a local name which is the Rails' way
Take a look at this Rails Best Practice. Using local variables is preferable way when rendering partials (those view files which start with a _). That's because you'll need review your controller's code to know about instance variable.
What's the best way to dynamically create a controller in Rails.
I've got a class that needs to generate a bunch of controller that inherit from it. I could just create a bunch of files in /app/controllers, but they'd all be basically empty files. There's got to be a way to generate these classes dynamically and have them treated like other controllers in Rails, e.g. reloaded correctly in dev mode.
I tried putting this in a config/initializer:
FL.contact_types.each do |contact_type|
controller_name = "#{contact_type.pluralize}Controller"
Object.const_set(controller_name.to_sym, Class.new(ContactsController)) unless Object.const_defined?(controller_name.to_sym)
end
This worked, but I run into the dependency/reload problem and get “A copy of AuthenticatedSystem has been removed from the module tree but is still active” since the ContactsController inherits from ApplicationController which includes AuthenticatedSystem.
Is creating a bunch of empty files really the best solution?
Are you sure you need multiple controllers? Can you have a single controller that gets passed a value to indicate how it behaves? You could also make a module that has the common functionality in it, and have the empty controller files that only reference the module.
a route could be used to pass the type in:
map.route "/:type_of_contact/:action/:id/, {:controller => :contact_type}
now in all the actions, in params you have the key :type_of_contact to guide your system.
You'll want to make sure this is near the end of your routes so it doesn't override access to your other controllers.