Controller variables are not recognizable in some views - ruby-on-rails

How to pass variables between the application controller and different views in Ruby on rails ? Is there any global scope which helps us to keep track of any variable created in the controller and use it in any view code in the same application ?

To use a method from the application controller in a view, mark it as an helper method.
Something like this
class ApplicationController < ActionController::Base
def current_user
#current_user ||= User.find(session[:user_id])
end
helper_method :current_user
end
Now, the current_user method is accessible in all views and it can be used to get the #current_user instance variable.

Simply Write your code in application helper and it will be accessible through out any view in application..

please read http://guides.rubyonrails.org/action_controller_overview.html (Especially part 3)
This is not the best option though, I recommend reading about exposing you variables in controllers.
https://github.com/hashrocket/decent_exposure
or
https://github.com/netguru/decent_decoration
are created just for that and I recommend them.

A variable declared like so:
#current_user
for example will be available in any views as long as the method that creates that variable is called in the controller for that view.
You can read more about ruby variables here http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/variables.html

Related

Add helper to rails controller instance only

I have some helpers that are defined on runtime that are specific for a single call, e.g. a single instance of a controller (the next call could have different helper methods). Is there a robust way to add a helper method to an instance of a controller and it's view only, without adding the helper to other instances and views of this controller?
To define a helper for ALL instances, you could use the .helper_method method, e.g.
class Article < ApplicationController
helper_method :my_helper
def my_helper
# do something
end
end
I digged around in the source code, and found the (fairly private looking) #_helpers method which returns a module that contains all helpers for this instance. I could now use some meta programming to define my methods on this module
def index
_helpers.define_singleton_method(:my_helper) do
# do something
end
end
But I don't like this approach because I'm using a clearly private intended method that could easily change in the future (see the leading _).
If I only needed the helper inside the controller instance only, I could just call #define_singleton_method on the instance directly, but this doesn't make it available to the view.
So I'm looking for an official "Rails way" to define a helper for a single instance of a controller and it's view, like Rails provides with it's class method .helper_method.
I'm not sure if there is an official Rails way of doing this.
You could create an anonymous module and extend from that. Since this solution uses pure Ruby, you'll have to extend both the controller and view.
before_action :set_helpers, only: :index
def index
# ...
end
private
def set_helpers
#helpers = Module.new do |mod|
define_method(:my_helper) do
# do something
end
end
extend(#helpers)
end
<% extend(#helpers) %>

rails service object with current_user

I am using devise and have created a service object - everything works as expected and perfectly. However I want to know how I would include the current_user? as the moment I have to always pass in the current_user or user_signed_in? variables which is annoying when I am using the same methods in different classes and views how would I go about doing this?
Currently I have this for testing:
class User
class GetStart
attr_reader :current_user
def initialize(user)
#current_user = user
p current_user
end
end
end
current_user is usually a helper method of ApplicationController which means it will only be accessible within your controllers and views. This is a good thing -- your service object has no business accessing current_user directly since current_user is created from information passed in the request/session which is a concern of the controller.
In my opinion, your approach is correct, it's preferable to pass your user object in as an external object (i.e. dependency injection) than directly couple it to method within a separate object. After all, does your service object need to know or care whether user is from the session?
Also, as was mentioned, keep in mind that attr_reader creates an instance variable for the class, so you should have #current_user = user.

using helper_method AbstractController::Helpers::ClassMethods in a model

In my application controller I have the following code:
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user]) if session[:user]
end
I would like to use the "current_user" method in a model. According to the rails API the helper method can be accessed at "AbstractController::Helpers::ClassMethods".
See link:
http://api.rubyonrails.org/classes/AbstractController/Helpers/ClassMethods.html
When I add this to my model I get a method not found error:
include AbstractController::Helpers::ClassMethods
Am I missing something in how to include these helper methods?
Thanks!
Short answer: you can't and you shouldn't.
The model doesn't have (and should not have) any visibility of the view and the controller. The clear separation is one of the key principle of the MVC pattern.
If you want a method in your model to have access to the current user, then pass the user when invoking the method.
For instance, assuming you want to pass the user on the Post creation, define a custom method
class Post
def do_something_with_user(user)
# ...
end
end
and call it from the controller
def action
Post.find(...).do_something_with_user(current_user)
end
There are possible workarounds, such as storing the current user into the current thread or in a global variable, but this is gonna break the rules (and you should not break the rules).

How to ensure an object is always available in a view?

I have some code in my application layout view that requires an object to exist in order to work. The object exists on some controllers, but not all.
At first I thought I could use the after_filter on the application_controller to ensure that the object exists. But this didn't work because the after_filter is only applied after the view is rendered and it is apparently an anti-pattern as well.
What is the best way to ensure that the object always exists, without unnecessarily creating the object on controllers that already create the object.
Say your variable is #foo.
application_helper.rb
def foo
#foo ||= generate_foo()
end
then from any view, you just call your object by foo and not #foo.
This might have it's own pitfalls as well but personally, I will create a method in my application_controller to return the instance. To make it available in the views, just pass the method to helper_method. helper_method is used to share methods between views, helpers and controllers.
I mostly do this with authentication. So you I will have something like;
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
helper_method :current_user # make current_user available in the views

How do I dynamically create a named_route in rails?

I currently have this in my ApplicationController
def account_path
eval "#{current_user.type.downcase}_account_path"
end
I use it for redirects, etc. But I also want to use it in the view (for link_to's etc). Is this is a legit case to share code between the controller and view to keep it DRY even though it breaks MVC?
Yes, I'd say that's a legitimate re-use. The helper_method call is there for a reason so:
helper_method :account_path
will make this available to your views too.
If you prefer not to use eval you could do:
def account_path
self.send("#{current_user.type.downcase}_account_path")
end
as the _path method is interpreted as a method on the controller.

Resources