ApplicationHelper not loaded in Rails 4 engine - ruby-on-rails

Long time reader of SO here. I'm working on a Rails Engine. The big picture problem is that I get a NoMethodError on a helper method living in my Engine's ApplicationHelper. This is for work so I'm going to call the engine Blorge.
I have my helper method that is causing issues anywhere it is called. The Helper method is returning a NoMethodError. I thought maybe I needed to manually add helper Blorge::ApplicationHelper to Blorge::ApplicationController but the issue is still happening.
Am I missing something fundamental about Engines here?
Here is some actual code to give you a better idea of what I'm looking at.
index_header partial
app/views/blorge/shared/_index_header.html.erb
# require_locals is the helper method in question here
<% require_locals ['title'], local_assigns %>
<% title = title.pluralize %>
<section class="main_content-header">
<div class="main_content-header-wrapper">
<%= content_tag :h1, title %>
<div class="main_content-header-save">
<%= link_to "New #{title.singularize}", #new_path, class: "add-button" %>
</div>
</div>
</section>
Pages#home view
app/views/blorge/pages/home.html.erb
<%= render 'blorge/shared/index_header', title: "Welcome, #{current_user.full_name}" %>
...
Engine Application Helper
app/helpers/blorge/application_helper.rb
module Blorge
module ApplicationHelper
def require_locals(local_array, local_assigns)
local_array.each do |loc|
raise "#{loc} is a required local, please define it when you render this partial" unless local_assigns[loc.to_sym].present?
end
end
end
end
Engine Pages Controller
app/controller/blorge/pages_controller.rb
module Blorge
class PagesController < ApplicationController
def home
end
end
end
Engine Application Controller
app/controllers/blorge/application_controller.rb
class Blorge::ApplicationController < ActionController::Base
helper Blorge::ApplicationHelper
...
end
If I restart the server and reload the page, it will usually work just fine, and once it works, the issue doesn't come back for a couple days. After reading Helpers in Rails engine and Rails Engines: Helpers only are reloaded when restarting the server it sounds like I need to include the helper in my application controller with the to_prepare method in my engine.rb file. I am going to try this next but I most want to know if I'm missing something very basic here, If i do just have to add it to engine.rb, can someone explain why?
This might have been too much information, but I'd rather give more than not enough. Thanks in advance.
Edit
the fix seems to have been adding the helpers to application controller within engine.rb. I suspected this would be the fix, but I still have no clue why this is. Does anyone know why I should have to do this?
The Solution
config.to_prepare do
ApplicationController.helper(MyEngineHelper)
end

Related

Are application helper methods available to all views?

Rails 4.1
Ruby 2.0
Windows 8.1
In my helpers/application_helper.rb, I have:
def agents_and_ids_generator
agents = Agent.all.order(:last)
if agents
agents_and_ids = [['','']]
agents.each do |l|
name = "#{l.first} #{l.last}"
agents_and_ids << [name,l.id]
end
return agents_and_ids
end
end
In my views/agents/form.html.erb, I have the following:
<%= f.select :agent_id, options_for_select(agents_and_ids_generator) %>
In my controllers/agents_controller.rb, I have the following:
include ApplicationHelper
But when I go to this view, I get the following error message:
undefined local variable or method `agents_and_ids_generator' for #<#:0x00000006fc9148>
If I move the agents_and_ids_generator method to the helpers/agents_helper.rb, it works fine.
I thought that by putting methods in the application helper and including the application in a controller, then these methods are available to the views. Am I incorrect in that assumption?
Answer:
Making sure that application helper is not included in controllers, and added the following simplification:
<%= f.collection_select :agent_id, Agent.all.order(:last), :id, :name_with_initial, prompt: true %>
#app/models/agent.rb
Class Agent < ActiveRecord::Base
def name_with_initial
"#{self.first} #{self.last}"
end
end
Helpers
The bottom line answer is the application_helper is available in all your views.
Rails actually uses helpers all over the place - in everything from the likes of form_for to other built-in Rails methods.
As Rails is basically just a series of classes & modules, the helpers are loaded when your views are rendered, allowing you to call them whenever you need. Controllers are processed much earlier in the stack, and thus you have to explicitly include the helpers you need in them
Important - you don't need to include the ApplicationHelper in your ApplicationController. It should just work
Your Issue
There may be several potentialities causing the problem; I have two ideas for you:
Is your AgentsController inheriting from ApplicationController?
Perhaps your inclusion of ApplicationHelper is causing an issue
Its strange that your AgentsHelper works, and ApplicationHelper does not. One way to explain this would be that Rails will load a helper depending on the controller which is being operated, meaning if you don't inherit from ApplicationController, the ApplicationHelper won't be called.
You'll need to test with this:
#app/controllers/application_controller.rb
Class AgentsController < ApplicationController
...
end
Next, you need to get rid of the include ApplicationHelper in your controller. This only makes the helper available for that class (the controller), and will not have any bearing on your view
Having said this, it may be causing a problem with your view loading the ApplicationHelper - meaning you should definitely test removing it from your ApplicationController
Method
Finally, your method could be simplified massively, using collection_select:
<%= f.collection_select :agent_id, Agent.all.order(:last), :id, :name_with_initial, prompt: true %>
#app/models/agent.rb
Class Agent < ActiveRecord::Base
def name_with_initial
"#{l.first} #{l.last}"
end
end
Rails 5 update. I ran into a similar issue with views not picking up a method from application_helper.rb. This post helped me. The files that are provided in the helpers directory of a new rails app are for those views only. Methods in the application_helper.rb will not be available automatically to all views. To create a helper method that is available to all views, create a new helper file in the helper directory such as clean_emails_helper.rb and add your custom method here like this:
Module CleanEmailsHelper
def clean_email(email)
*do some stuff to email*
return email
end
end
Then you can call <%= clean_email(email) %> from any view in your app.

How to use "impressionist" gem in Rails?

I am new to rails dev and is looking to use https://github.com/charlotte-ruby/impressionist but not able to figure out how to use it looking at its documentation. I have done the migration and when trying to put
class ArticlesController < InheritedResources::Base
impressionist
end
OR
class ArticlesController < InheritedResources::Base
impressionist :actions=>[:show,:index]
end
it is throwing no method found error. I am unsure which code needs to be put in model, which to be in controller and which to be in views to see view_count, any help ?
the first question was a type
and as for your second question (inside the comment) the easiest but very efficient way would be
in the view:
<% #pages.each do |page| %>
<%= page.impressionist_count %>
<% end %>
You can also use Impression as a model to query stuff, just like normal models. For example,
Impression.where(user_id: 12).length
I find this is handy if you need some advanced queries.
The documentation does not specify to re-start server. This is not obvious as it does not apply to all gems, however it is required for impressionist.

Can't suppress output in nested block helper in rails 3

This one is sort of twisting my noodle.
I have something resembling this (in a rails 3 engine if that matters)
class Builder
def initialize
#foos = []
end
def foo(&block)
#foos << helper.capture(&block) #helper being a class that is including ActionView::Helpers
end
def to_html
#foos.join "\n"
end
end
module ApplicationHelper
def widget
b = Builder.new
yield b
b.to_html
end
end
#in a view somewhere
<%= widget do |b| %>
<% b.foo do %>
static content
<% end %>
<% end %>
Everything is working out great, but that nested static content is getting output twice -- once where I want it, and once where widget was called.
From what I have read, capture is supposed to deal with this exact problem. I am pretty sure the problem stems from how I am calling capture (from a dummy proxy class that includes ActionView::Helpers), but the problem is that b.foo call is calling a method on a class instance, not from the context of something that will be mixed into the template.
Is there any way to get around this problem? Or am I approaching this from the wrong direction. I am trying to model something fairly involved and am really happy with the api, just can't seem to get passed this problem.
If you modify the helper method to pass in self, which would be the current view instance, and then use this to capture, you might not have this issue. Substitute your use of helper for the provided view instance.

Template path in Rails 3

Let's say, I connected the route / to WelcomeController's index action.
Inside of the index.html.erb-Template I want to display the path of the template from Rails.root upwards, ie.
<h1> We are rendering: <%= how_do_i_do_this? %></h1>
to render to
<h1> We are rendering: app/views/presentation/index.html.erb</h1>
In Rails 2 I could access template.path, but this doesn't work anymore
Any ideas?
Because of how template rendering works in Rails, you will now be able to use __FILE__ for this instead. This works for me:
<%= __FILE__.gsub(Rails.root.to_s, "") %>
There may be a better way to do this however, but I couldn't find it when I went looking.
Ryan's answer works. If you also want to put your method in a helper, use Kernel#caller. Here is a method I'm using to do something similar:
def has_page_comment? code = nil
if code.nil?
# grab caller file, sanitize
code = caller.first.split(':').first.gsub(Rails.root.to_s,'').gsub('.html.erb','')
end
...
end

What is the best way to avoid code duplication between views and controllers in Ruby on Rails?

I currently have code in my ApplicationController to check if a user is logged in and has the required access to perform a given action (the tests take place in a before_filter).
I require the same functionality in the views to decide if I should be showing the admin links in a list view, but how do I best avoid duplicating code in the controllers and views?
The way I have chosen to do it now, is to have the user_can_edit_customers? essentially be a wrapper for 'can_edit_customers?' on my User class:
ApplicationController:
class ApplicationController
And then do something similar in my view helpers.
This way all functionality is encapsulated in the User model but I still need to define wrappers in my controllers and helpers, but are there smarter ways of doing this?
Note, the user stuff is only an example - this also applies to other pieces of functionality.
I would say do away with the wrappers and just call can_edit_customers? directly on the user object passed to the view.
If you want to keep them a solution might be to use helper_method in your controller.
helper_method :current_user, :can_edit_customers?
def current_user
#current_user ||= User.find_by_id(session[:user])
end
def can_edit_customers?
#current_user.can_edit_customers?
end
This way the method also becomes available in the view.
<% if can_edit_customers? -%>...<% end -%>
Just to be more direct. The helper_method "macro" in a controller causes a controller method to behave as if it's also a method in the application helper.
helper_method :current_user, :can_edit_customers?
Personally I think you should not use helpers.
I would take a different solution.
Let's say that we have Cucumber, a model, that should not be editable by some users. I create #editable? method as follows:
class Cucumber < ActiveRecord::Base
def editable?(current_user)
# Something happens here.
end
end
Note that if a page is accessible by everyone, current_user might be false.
Then, in the views you're able to do:
<%- if #cucumber.editable?(current_user) -%>
<%# Something happens here. -%>
<%- end -%>
And, in the controllers, use a filter.
The best thing about this approach is that it follows Fat Model, and enables you to easily cover your permissions with unit tests.
I think helpers are the way to do what you want. As for checking in views whether the user has or not the priviledge to do something, you could put a flag in your session data (e.g. session[:admin] = true and check that in your view.
It is common practice to make methods like logged_in? available in the controller and the views. For most cases, you don't need to push down authorization logic into the models.
Definetly go with with the approach user Hates described. Have a look at plugins like restful_authentication and acts_as_authenticated, to see how they did it.
There are several railscasts (http://railscasts.com/episodes?search=authentication) covering this topic. For instance, you could write a helper that takes a block and is then used like this:
<%- admin_user_ do %>
<%= link_to .. %>
<%= link_to .. %>
<%= link_to .. %>
<%- end %>

Resources