Can I use other helpers methods in application_helper.rb? - ruby-on-rails

I have a question about the availability of methods defined in app/helpers.
Can I share methods in helpers, (for example, use methods defined in my_helper.rb in application_helper.rb), or are they restricted to views ?

You should be able to do that if you have this in controller or application_controller:
helper :all
But it seems a little too complex to have helpers that call out to other helpers, generally helper methods should be short simple and have little dependencies, they should do one simple thing for the view, each. Makes it harder to test I suppose if you have helper methods that call out to other helpers.
If the problem you are trying to solve with this is sufficiently complex I'd suggest trying to move it to a module in the lib directory and then include that module in the helpers that need the common functionality.

Related

rails 3.1, how to use before_filter to call method at a helper?

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)

RoR: defining a class inside a view helper file

I have a view helper file, app/helpers/analysis_helper.rb, whose toplevel methods I've been using in various view files. Works fine. I then defined an AnalysisSummary class inside analysis_helper.rb to package up some view-specific functionality.
However, when I try to instantiate an AnalysisSummary in a view file, I get the error:
uninitialized constant ActionView::CompiledTemplates::AnalysisSummary
Perhaps Rails is telling me that I shouldn't be defining a class inside a helper file? If so, where would you suggest parking AnalysisSummary? It's not a controller, it's not a model...
Thanks.
In Railscasts #213 (Revised) (subscribers only link, alas), Ryan Bates provides an example of how (and why) you might include a class within a helper. The basic gist is this:
# app/helpers/calendar_helper.rb
module CalendarHelper
def calendar(date = Date.today)
Calendar.new(self, date).render
end
class Calendar
def render
# Calendar, render thyself
end
# ... additional methods called by #render
end
end
To those opposed to classes within helpers, what do you make of Ryan's choice? Helpers are for generating markup, right? So if all the logic within class pertains to rendering (rather complicated) HTML, I would think that what it does (as opposed to what it is) makes it appropriate for inclusion in a helper.
Why does it need to be a class? Why not just a collection of methods? That's what a helper is: a collection of helpful methods. Business logic does not belong in helpers. You can place your code in a module within the helper file if you want to give some more structure and organization, though.
You can put classes in app/models without it having to be an ActiveRecord class, but you should seriously consider what the purpose of your class is before you place it there.
If it concerns only rendering the view, and not accessing data directly, it belongs in the view or a view helper.
You can call the class by explicitely mentioning the helper name
ApplicationHelper::AnalysisSummary.new
But I dont think it is a good idea to have classes in helpers.
It's a module then :) Definately do not define classes inside helpers. Jsut use a simple module to do the job.

View helper link_to in Model class

Using Rails 3, is there a way to use link_to helper, or any helper for that matter, inside model?
There are some reasons that you may need link_to in a model. Yes, #andy, it's a violation of MVC, but that doesn't mean you should get points for not answering the question.
#schwabsauce, it's easier than that. The first line isn't even strictly necessary if you do it in an initializer or something. Same thing works for .sanitize and .raw and a whole load of other awesome functions.
ActionView::Base.send(:include, Rails.application.routes.url_helpers)
ActionController::Base.helpers.link_to(whatever)
If you want to use autopaths you may have to do this inside your link_to:
Rails.application.routes.url_helpers.page_path(#page)
Be very careful following the advice outlined in Chuck's post if you're doing this in Rails 3.2.1 . It would seem as though that approach is not a safe way to go about including the link_to helper in non-view classes in Rails 3.2.1. There is a safer way (that works for us in any case) outlined below.
When we used the approach in Chuck's post in one of our classes, it ended up having very troubling and difficult to debug consequences. It ended up causing side effects / bugs that only turned up in very specific (and rare) circumstances.
The problem, as far as we can tell, is that this line:
ActionView::Base.send(:include, Rails.application.routes.url_helpers)
Is telling ActionView::Base to include the Rails.application.routes.url_helpers, which ActionView::Base apparently already does on its own. Having it include the url_helpers a second time, seems to cause re-initialization of the routes state (#_routes in classes that have included the ActionDispatch::Routing::UrlFor module).
This leads to seemingly random and unexplained "undefined method 'url_for' for nil:NilClass" exceptions in views that attempt to call, directly or indirectly, the url_for method after ActionView::Base has included the url_helpers the second time.
The solution that worked for us was instead of telling ActionView::Base to include the url_helpers again, just include the UrlHelper module yourself wherever you might need it.
Then when you need to use link_to and have access to the path you can simply do this (assuming login_path is valid for your app):
include ActionView::Helpers::UrlHelper
...
link = link_to('here', Rails.application.routes.url_helpers.login_path)
It took us a very long time and quite a lot of head scratching to track down the bugs caused by the double-include and I just wanted to warn others to be careful when tweaking the behavior of the Rails base classes.
I got this to work with the following inclusions:
include ActionView::Helpers::UrlHelper
include ActionController::UrlFor
include Rails.application.routes.url_helpers
cattr_accessor :controller
def controller; self.class.controller; end
def request; controller.request; end
Then in my controller I populated the attribute (creating a controller from scratch requires a significant amount of data in the arguments hash).
Lead.controller = self
link_to helper, MVC violation
What Andy said,
if you're generating HTML in the model you probably need to take a big long look at what you're doing and why.
URL helpers
URLs on the other hand often come in handy outside of view-controller code, in all kinds of service/form/api/... classes for example, even in models if you have to.
Yes, Rails.application.routes.url_helpers is a module, but that doesn't mean you should just include it wherever or funny stuff will start happening as Gary put it:
https://www.destroyallsoftware.com/blog/2011/one-base-class-to-rule-them-all
What you can do is:
delegate :url_helpers, :to => 'Rails.application.routes'
and then use, for example
url_helpers.home_url
If you want to use any module stuff anywhere and don't mind going against all Ruby norms, throw this hackery into a service:
module View
extend self
class HelperIncluder
include ActionView::Helpers::UrlHelper
end
def link_to(*args)
HelperIncluder.new.link_to(*args)
end
end
And now:
View.link_to('a', 'b') => "a"
Not without hackery.
If you think you need link_to in a model, you're likely violating some principle of the Model-View-Controller architecture.
A model should be a place for data and business logic, but generating links is almost certainly a job for the controller or view (or, Rails specifically, in a helper class).

Rails helper for views and controllers?

I know there are ways to make helpers available to controllers, but that this is generally bad form. How should the following be re-worked to avoid this?
I have a Contacts helper called "fullname" that combines a contact's first and last names.
A layout partial called subheader is rendered in the application layout, and contains this code:
<section id="subheader"><%= #subheader %></section>
The controllers set the value of #subheader.
The issue is that I often want "fullname" in #subheader. But this means accessing the helper from the controller. Should this fullname method reside somewhere else?
With something like fullname I usually just define a method on the model itself.
If the fullname method did some type of HTML formatting then I would keep those parts inside a helper.
Since the title of your question might attract viewers looking for a different answer, I'm going to answer the question of "can I use rails helpers in my controllers"? There are legitimate uses for this, so here's the cleanest way to do so:
In the helpers file, wrap the code you want to access in a model like so:
module HelperModuleName
[helper code here]
end
Wrapping only the code you need to use in your controllers (as opposed to including all helpers using include ApplicationHelper) is a good idea because it reduces the possibility for method name clashes and forces you to be more deliberate about your choice to use helpers in controllers.
Now include the module in your application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery
include HelperModuleName
end

Where to place Rails code that is not a model, view, controller or helper?

I want to share code not related to views between several controllers in my Rails app. Where in the directory structure should I place it?
EDIT: the code in question if something all controllers use to determine how they render the model data
If the code is something like modules with utility methods in these could be placed in the lib folder. Alternatively you could create a common superclass for some of your controllers if they share behaviour.
Please post an example of the kind of code you're thinking of.
If it's "something all controllers use", I would place it in a base class used by all controllers. The "application_controller" comes to mind.
I have been creating modules in lib to provide code to other classes.
Here's an abbreviated example module that defines values for views that can be instantiated from different controllers.
module ControllerDefaultValues
def default_value_for_some_controller()
#controller_name = "some_controller"
end
end
To use this, simply include the module in your class:
class SearchesController
include ControllerDefaultValues
#
def search_some_controller
default_value_for_some_controller()
render(:partial => "search_results")
end
end
The main benefit of this method is it keeps your controllers directory focused on controllers and your models directory focused on logic.
Personally i think its fine, if its controller related to put it in your controllers directory, but, labelled as a module, e.g. app/controllers/what_am_i_module.rb since it is specific to the application in development.
lib seems like a place to me where i would put framework/core enhancements or monkey patches which are non-specific to the application.
If it's going to be used by all your controllers, stick it in application_controller.rb
All your controllers inherit from ApplicationController, so they'll all have access to them.

Resources