Include ActionController::Base outside of views directory - ruby-on-rails

I can have a view file that contains only this:
root/app/views/layouts/application.html.erb
<%= link_to root_url %>
And of course it works. This is because
ActionController
is included in the view file somehow.
How does this work? Inside each view we don't write 'include ActionController' so how is it magically included?
Let's say I'm using an angular template:
root/app/assets/templates/angularview.html.erb
<%= link_to root_url %>
Everything works perfectly apart from the fact that the link_to isn't included in this view:
undefined method `link_to' for #<#<Class:0x000000020417b0>:0x0000000468f2c8>
How should I include ActionController into a file stored at root/app/assets/templates/angularview.html.erb?
What should I edit in my project to automatically make all files inside root/app/assets/templates include ActionController? Is this possible? I want them to behave like 'normal' views, and magically include everything a normal view includes.

It is not working as you have your angularview template in assets directory(as you have mentioned in your question: root/app/assets/templates/angularview.html.erb). You need to create it inside your application's app/views/layouts/ directory.
See these answers for more information:
https://stackoverflow.com/a/6951986/645886
https://stackoverflow.com/a/19849989/645886
UPDATE: However, if you must do that then you can create an initializer and put this code:
Rails.application.assets.context_class.class_eval do
include ActionView::Helpers
include MyAppHelper
include Rails.application.routes.url_helpers
end
Source: https://stackoverflow.com/a/14284279/645886

Related

Where to add shared view files in Rails 5?

I am using Rails 5 and I want to use shared files in my project. I have searched the web about this, and I got some results as follow:
For Rails 3
app/views/shared
For Rails 4
app/views/application
but there was nothing for Rails 5.
I am talking about the standard; is there any specific location to add common view files in Rails 5, just as we do in other frameworks? Like in Laravel there is a layout folder?
All the people telling you that there is no "standard location" for common view files are correct. However, if you want to ask Rails where it would go looking for a partial file if you attempted to render one on the view, just take any view file you have and render a partial you know doesn't exist.
If you have, say, a UsersController with a view structure that looks something like app/view/users, and you add the following on any view there:
<%= render 'foo' %>
You'll likely get an error that says something like:
Missing partial users/_foo, application/_foo
That means that whenever you attempt to render a partial by just it's name without any path information, Rails will look for it
first under the view directory for the current controller, in this case users
then under the application directory
So, I guess then you could say that the "default location" in Rails for common view files is under the application directory.
It's possible to add to this in order to create your app's own "standard location" for common view files by overriding the ActionView::ViewPaths.local_prefixes private class method that gets mixed in to every controller in Rails:
class ApplicationController < ActionController::Base
def self.local_prefixes
['shared', controller_path]
end
private_class_method :local_prefixes
end
class UsersController < ApplicationController
def self.local_prefixes
[controller_path]
end
private_class_method :local_prefixes
end
Now, your error will say something like:
Missing partial users/_foo, shared/_foo, application/_foo
which shows that Rails will check the shared directory for partials as well before it goes looking in the application directory.
Note that this method override should happen in both the controllers, otherwise the local_prefixes in UsersController get inherited from ApplicationController and you end up with duplicated lookup paths that look like:
shared/_foo, users/_foo, shared/_foo, application/_foo
If all this is too much effort/too weird, as other people have pointed out, you can always just specify your shared partial directory manually when you render a partial:
<%= render 'shared/foo' %>
You can create new directory in app/views directory and add your shared file in that directory.
Ex:
app/views/shared # Contains all shared/partial pages
Now create your partial page in app/views/shared directory
like: app/views/shared/_my_shared_view.html.erb
Now if you want use this shared view in any view just add the below code.
<%= render :partial => 'shared/my_shared_view' %>
That's it. Hope this will help you.

Accessing Helper methods in an Admin Controllers

so I have the following
# app/helpers/experts_helper.rb
module ExpertsHelper
....
def twitter_link(expert)
link_to expert.twitter_url, class: 'social-link', target: '_blank' do
content_tag(:i, '', class: 'fa fa-twitter expert-fa')
end
end
def linkedin_link(expert)
link_to expert.linkedin_url, class: 'social-link', target: '_blank' do
content_tag(:i, '', class: 'fa fa-linkedin expert-fa')
end
end
end
I can access these methods in all my views inside views/experts/... but not in those inside views/admin/experts/... How can I access these them? Thanks
EDIT 1:: Corrected some typos, also I want to be able to use these helper methods on class Admin::ExpertsController < AdminController (content omitted for brevity) end I have used include ExpertsHelper inside the controller, but it doesn't solve it
EDIT 2: I have tried all proposed solutions but still don't get anything to be displayed.
I have tried the include ExpertsHelper and the include ApplicationController.helpers.method, with the latter I get TypeError - wrong argument type Array (expected Module): and with the former I don't get any errors, but I don't see anything being displayed on the page, no icons, no photos, nothing. I even tried copying the helper methods inside module Experts inside the module Experts::AdminHelper end, but still nothing.
I hope you are looking for this. Add this line in the controller where you want to access helper methods.
include ApplicationHelper
I believe you can use ActionView::Rendering#view_context to use those helper methods. In your controller you would use them like so:
view_context.twitter_link(expert)
view_context.linkedin_link(expert)
See this other SO question for more details and options.

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.

Ruby on Rails - using helpers in html.erb

I'm probably missing some things.
Say for example I have a helper function in app/helpers/foo_controller.rb and the code is as follows:
def sample_helper(count)
#implementaton...
end
and I want to use this helper in a webpage generated by rails and the code is as follows:
<%= sample_helper(user.id) %>
and if I try to run the webpage it will throw me an error saying that the method is not defined.
Thanks in advance!
You don't quite have the naming conventions right.
Name your helper file app/helpers/foo_helper.rb and in it you should have this:
module FooHelper
def sample_helper(count)
"#{count} items" # or whatever
end
end
And now, from any view rendered by FooController you should be able to use the sample_helper method.
Also, you should know that if you use the rails generators this structure is setup for you. All you need to do is add methods to the files that get generated. That way you don't need to guess the naming conventions.
For example, this command will make a controller file, controller test files, a helper file, and and an index view file, all ready for you to customize.
rails g controller foo index
Is your helper should be in a file called app/helpers/foo_helper.rb that contains a a module of the same name as the helper (camelized) Like:
module FooHelper
def sample_helper(cont)
# implementation
end
end
That's the way Rail auto loads helpers.

Rails: Proper way to add functionality to rails methods

I'm just starting to tinker with extending the rails framework, and as an experiment, I thought I'd add some extra info inside the form_for helper. Specifically, when form_for is called, I'd like to generate an extra h1 tag such as:
# regular form_for <form> opening tag
<h1>Woohoo! It's added!</h1>
# tags fed into form_for via &proc
# form_for close <form> tag
At the moment I've added a /lib file that opens up ActiveRecord::FormHelper and overrides "form for". Needless to say writing out the whole form_for method with just the one added line added is dog ugly...but I can't call super() because, well, instead of inheriting from the method I'd like to super(), I've just overwritten it in /lib.
So, assuming I stubbornly want the functionality to be called via the same form_for tag (instead of, for example extended_form_for), what's the standard way for calling back to the original form_for method I'm overwriting? alias_method_chain? Thought I'd ask before I cement in some potentially lousy practices. If any hardened veterans could give an example I'd be appreciative.
Cheers
You could override form_for in your ApplicationHelper:
module ApplicationHelper
def form_for(*)
content_tag(:h1, "Woohoo! It's added!") + super
end
end
alias_method_chain is by far the simplest way to overwrite the method while still being able to call the original method. So in your lib file you'll want something like this:
def form_for_with_header(...)
form_for_without_header(...)
content_tag(:h1, "Header tag here")
# etc...
end

Resources