ruby on rails - use a helper in html.erb - ruby-on-rails

I have a html.erb file used for an email template.
Is there any way to include a helper module and use it's methods within this file?
Something like:
a mails_helper.rb file:
module MailsHelper
def mail_to
"foo"
end
end
and in mail_template.html.erb:
<% include MailsHelper %>
<h2> This mail was sent to: <%= mail_to %> </h2>

Add helper :mail to the top of your ActionMailer derived classex:- app/mailers/mails_mailer.rb
class MailMailer < ActionMailer::Base
helper :mails
...
end
Checkout this answer

Name the helper file with same prefix as the ActionMailer's file name.
For example:
mailer: users_mailer.rb helper: users_mailer_helper.rb
According to the ruby on rails naming conventions - any view rendered by UsersMailer would have access to your helper methods.

Related

rails how to use helpers with ERB.new in service?

I have a service that uses an ERB file to render a template form.
In the form I use several helpers, but they don't seem to be available in this context.
how could I use my helpers in the rendering via ERB.new(template).result(binding) ?
this is the error I'm getting:
*** NoMethodError Exception: undefined method `image_encoded' for #<MyService>
here's the call in the service app/services/my_service.rb file:
ERB.new(template).result(binding)
here's my helper app/helpers/my_helper.rb:
module MyHelper
def image_encoded(image_url)
<<image stuff>>
end
end
here's my call to the helper in the app/views/my_template/my_template.html.erb file:
<img src="<%= image_encoded(image) %>"/>
In your service your helpers are not included by default. You can include the methods from a particular helper like this:
class MyService
include MyHelper
end

How to use a rails helper in a PDF template inside services layer?

I have a PDF template and I need to use a view helper method inside a HTML file that is in the services folder to generate the PDF. However, when I try to use the default view helpers, I get an exception that the method doesn't exist.
ActionView::Template::Error: undefined method `helper_method' for #<#<Class:0x000000000e309bd0>:0x000000000e3a0350>
How can I make this work?
You can make your module methods work as they were class methods by using
module_function :method
The code looks like this:
module Helper
def helper_method; end
module_function :helper_method
end
Then in your html.erb you do this:
<% Helper.helper_method %>

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.

What is the right way to embed image into email using Rails?

What is the right way to embed an image into email using Rails?
I combined the answer from Oksana with a custom helper approach and got the following to work quite nicely.
app/helpers/email_helper.rb
module EmailHelper
def email_image_tag(image, **options)
attachments[image] = File.read(Rails.root.join("app/assets/images/#{image}"))
image_tag attachments[image].url, **options
end
end
app/mailers/base_mailer.rb
class BaseMailer < ActionMailer::Base
helper(EmailHelper)
end
app/mailers/my_mailer.rb
class MyMailer < BaseMailer
def send_my_mail(email)
mail to: email, subject: "My Subject"
end
end
Then for example where I want to attach the company logo in my email layout file I would use
app/views/layouts/email.html.erb
<%= email_image_tag("company_logo.png") %>
Note the **options makes the tag more extensible but it will only work in ruby >=2. To make this work in ruby < 2 you will have to use the older way of handling key word options.
Update 03/25/2022: Rails 6 no longer supports add_template_helper, and now replaces it with helper, as explained by this answer that links to the commit that did so.
RAILS 5
In your mail method add your inline attachment pointing to your image:
class ConfirmationMailer < ActionMailer::Base
def confirmation_email
attachments.inline["logo.png"] = File.read("#{Rails.root}/app/assets/images/logo.png")
mail(to: email, subject: 'test subject')
end
end
Then in your mail html view an image_tag with the attachment url:
<%= image_tag(attachments['logo.png'].url) %>
Adding onto Oksana and tdubs' answers
The module tdubs wrote works on desktop, but for the mobile gmail client, the images appeared as attachments. To fix this, do this for the
app/helpers/email_helper.rb
module EmailHelper
def email_image_tag(image, **options)
attachments[image] = {
:data => File.read(Rails.root.join("app/assets/images/emails/#{image}")),
:mime_type => "image/png",
:encoding => "base64"
}
image_tag attachments[image].url, **options
end
end
For the rest, follow tdubs's answer.
After a lot of research i have found very cleaner way to embed image in email.
Just add following line in production.rb and development.rb
config.action_mailer.asset_host = 'YOUR HOST URL'
In your view embed image by using following code.
<%= image_tag('My Web Site Logo.png') %>
Note: Make sure to update YOUR HOST URL and My Web Site Logo.png in
above code.
For basic details of usage of Action Mailer, please refer to ActionMailer::Base.
Copy pasted from here
http://api.rubyonrails.org/classes/ActionMailer/Base.html#class-ActionMailer::Base-label-Inline+Attachments
Inline Attachments
You can also specify that a file should be displayed inline with other HTML. This is useful if you want to display a corporate logo or a photo.
class Notifier < ApplicationMailer
def welcome(recipient)
attachments.inline['photo.png'] = File.read('path/to/photo.png')
mail(to: recipient, subject: "Here is what we look like")
end
end
And then to reference the image in the view, you create a welcome.html.erb file and make a call to image_tag passing in the attachment you want to display and then call url on the attachment to get the relative content id path for the image source:
<h1>Please Don't Cringe</h1>
<%= image_tag attachments['photo.png'].url -%>
As we are using Action View's image_tag method, you can pass in any other options you want:
<h1>Please Don't Cringe</h1>
<%= image_tag attachments['photo.png'].url, alt: 'Our Photo', class: 'photo' -%>
In rails 6, if you use the solution of #Tyron, you'll need to replace add_template_helper with helper in the BaseMailer. So, it becomes:
class BaseMailer < ActionMailer::Base
helper(EmailHelper)
end
I don't know much about rails, but I've worked on projects in C# that create emails and then insert them in a users inbox via the Google APIs. To create the email, I had to generate the email string from scratch. If you enable multipart for the email, then the image bytes will be included in a multipart section using base64 encoding.
You may want to check out the TMail and RubyMail packages to see if they support these actions for you.

How do I call a Rails helper method from inside another helper method?

I am writing a helper that needs to call another helper, which generates html. How do I do that?
try:
include AnotherHelper
Just call it.
If it is in a different helper file, your controller can include the other helpfile by using the controller method "helper"
Added:
Here is an example:
# in the view
<%= my_helper %>
# in the helper file
def my_helper
"<div>" + someother_helper_which_generates_html + "</div>"
end
** Please add more details to your question if this isn't helping....
Something like this should help you (say, in application_helper.rb)
module ApplicationHelper
def create_div
html("this is some content")
end
def html(content)
"<div>#{content}</div>"
end
end
In this case, the create_div method is calling the html method with a string as an argument. the html method returns a string of HTML with the argument you supply embedded. in a view, it would look like:
<%= create_div %>
hope this helps!

Resources