I am using Ruby on Rails 3.1.1 and I am trying to translate email messages body. I created/stated all necessary "things" (YAML files, key/value pairs, ...) to make the I18n gem to work: email messages are sent without problems using the default language (:en).
Then I added a new language and made all that had to be done to make the I18n gem to work with another language and to get always a locale=de parameter in URLs.
class ApplicationController < ActionController::Base
before_filter :set_locale
def set_locale
if params[:locale] && I18n.available_locales.include?(params[:locale].to_sym)
I18n.locale = params[:locale]
end
end
...
end
However when I sent an email, even if the locale is properly set (eg: locale=de), sent email message are not translated (those still use the default :en language).
How can I make the I18n to translate email messages body?
I read the Localized ActionMailer Templates for Rails blog post
but it is old and I have not tested that...
I read the Rails I18n and emails blog post and I tested that. It works, but how can handle translation in my case (I am using the params method...)? Is there a better solution?
Solution
In your railsproject make a mailer (read http://guides.rubyonrails.org/action_mailer_basics.html how to make one). For example UserMailer.
rails g mailer UserMailer
Define a method for example mail_user.
def mail_user(user)
#user = user
mail(:to => "test example <testuser#testuser.com>", :subject => "hello")
end
Now define views. For example: mail_user.de.html.erb and mail_user.en.html.erb. Put your translations in there. If you want to translate variables seperatly use:
<%= I18n.t("foo.bar") %>
When you do this, ensure you have a en.yml and de.yml translation! Define a translation like the following example:
foo:
bar: hello
You should be ready to go.
How this works
ActionMailer works the following way. You can create mailer models which inherit from ActionMailer::Base. Like ActionController the models have associated views (templates) in the /app/views/ directory.
Now here is the technical part and why this all magicly works. ActionController and ActionMailer default include AbstractController::Rendering directly or indirectly (ActionController::Metal::Rendering). AbstractController::Rendering uses ActionView as default library for its template rendering engine and includes AbstractController::ViewPaths and an instance of I18n proxy to find localized views. To learn more i'd like to refer to the ActionPack source code on github.
To get to the point. ActionView allows you to use localisation in your templates: See Rails guide: Action View Overview , Chapter Localized views.
Related
I noticed that Mail gem doesn't get loaded outside ActionMailer context, but the gem is present in the proper gem group of Gemfile and then "loaded" upon Rails initialization.
To create a Mail object in a controller using Mail.new I need to put
require 'mail'
at the top of example_controller.rb, before
class ExampleController < ApplicationController
Could someone explain to me why?
Background:
I need to build an app whose functionality is primarily based on receiving emails of various types. I need to expose only one email address, where people will send all of these emails.
My mail server will pipe the raw email to a ruby script that sends the raw email as a POST request to my app.
Then, I need to identify which kind of email has arrived inferring that from its content (primarily attachments).
For example, let's have emails of types A, B and C. My email processing function will call one of three methods once it identifies the type of the email.
Where should I put the processing function?
You shouldn't be creating mail objects in your controllers. You should create a mailer and then call that mailer from your controller to send any emails you need to.
For example, say you have the following mailer in app/mailers/customer_mailer.rb:
class CustomerMailer < ActionMailer::Base
def send_reminder(user)
#user = user
mail to: user.email, subject: 'Reminder'
end
end
You can then call this from your controller as needed:
class ExampleController < ApplicationController
def some_action
#user = User.find(params[:id])
CustomerMailer.send_reminder(#user).deliver_now
end
end
This way your controller can focus on the implementations specific to controlling the request, and leave the mailer to worry about how to send email.
It's worth noting you also have access to a deliver_later method if you're using a background job runner.
Take a look at the documentation for more details: http://guides.rubyonrails.org/action_mailer_basics.html
Is it possible to embed serverside ruby to Opal .js.rb files?
In other words I need to access for example User.find(1) in some opal file in Rails, like one would do with .erb.
Works like this out of the box in Reactive-Record. Otherwise you have to build some kind of api between the client + v8 prerendering engine and the server to get the data (which is what reactive-record does.) You can look at reactive-ruby and reactive-record's code in the files labeled "isomorphic..." See the React.rb Reactive-Ruby branch readme for more info.
It sounds like you're looking for a way to pass data to the client in the initial request. If you load the data in the server app and just want to pass it along, you can look into the gon gem.
TL;DR version
Here's enough to get your feet wet
# Gemfile
gem 'gon'
# app/controllers/my_controller.rb
class MyController < ApplicationController
before_action { gon.push current_user: User.find(session[:user_id]) }
end
# app/views/layouts/application.html.erb
<head>
<%= include_gon %>
</head>
# app/assets/javascripts/application.rb
require 'native' # To be able to convert JS objects to hashes.
current_user = User.new(Hash.new(`gon.current_user`))
The explanation:
The gon gem sets up a hash that will be JS-objectified and placed into your JS runtime in the browser. For more info on that, see the Railscast about it (it's still mostly relevant, not much has changed).
In the browser, that JS object is also named gon, so gon.current_user would be whatever you set in gon.push current_user: some_user in the controller action (or before_action callback).
But we'll need to convert that from a JS object to a Ruby hash using Hash.new(gon.current_user), then you can pass that resulting hash to a User.new call.
The important part: you'll need to have a User class in your Opal app. If your Rails app sets up User an ActiveRecord model, you won't be able to reuse it, so you'll need to create a new one, but if it's just a PORO (plain-old Ruby object), you can add the following line to an initializer:
Opal.append_path Rails.root.join('app', 'shared')
Then you can put Ruby code that you want available in both your Rails app and your Opal app in app/shared. For example, you could do this in app/shared/user.rb:
class User
attr_reader :id, :name, :email
def initialize(attributes={})
attributes.each do |attr, value|
instance_variable_set "##{attr}", value
end
end
end
I have a RubyOnRails 3.2.x application that sends out mails using Actionmailer.
The code goes something like this:
class Mymailer < ActionMailer::Base
def sendout
mail(:to->"someone#somewhere.com", :from ...........
end
end
Instead of sending out that email, I want it to be rendered to a string which I then plan to process differently
PS: In my specific case I want to pass that string to a Node.JS server who will do the actual sending of the mail, I am using RubyOnRails to handle the multi language support and number formatting (yes I have multiple templates for the different languages that I support).
Since Ruby won't be doing the email sending, there's no need to use the Mailer.
Ideally you could generate a JSON string representation of the email like:
# at the top of the file
require 'json'
# then in your method
json_string = {
:to => "email#example.com",
:from =>"sender#example.com",
:body => "this is the body"
}.to_json
Then post this string to your node.js server from (for example) your controller or whatever is currently calling your mailer.
However, since you want to render the email using templates which pull in DB fields and use the i18n functionality of Rails, you could use the Mailer but render the result to a string like follows:
mail(to: "mail#example.com") do |format|
format.html do
string = render_to_string("your_template")
call_node_js(string)
end
end
If what you want is getting the whole mail representation, including headers, then you might want to browse the source code to see what happens behind the curtain.
A good starting point is the ActionMailer::Base method #mail (Rails 4):
http://api.rubyonrails.org/classes/ActionMailer/Base.html#method-i-mail
Anyway, if the sending is handled by Node.js, you don't need to do it. Just build a JSON object like Olly suggested and pass it through.
I know that this not an "acceptable" practice but as a background process I am caching a rendered Rails partial into the database for faster output via JSONP. I have found many resources on the topic and successfully output a Rails 2.3.x partial within a ActiveRecord model, BUT if I use dynamic URLs within a partial Rails blows up.
I get a successful output (minus the dynamic URLs) with this...
def self.compile_html
viewer = Class.new(ApplicationController)
path = ActionController::Base.view_paths rescue ActionController::Base.view_root
Question.all.each do |q|
q.html = ActionView::Base.new(path, {}, viewer).render(:partial => "questions/cached_output", :locals => { :question => q })
sleep 1 # hold for complete output and debugging only
q.save( false ) # bypass validations
end
return "Caching complete"
end
I have tried including ActionController::UrlWriter Modules and ActionView::Helpers::UrlHelper with no luck. I cannot seems to find the instantiation/inclusion order to allow the partial to access ActionController::Base.new.url_for() to write the dynamic routes to the partial.
I did attempt a similar process as RoR: undefined method `url_for' for nil:NilClass without luck
I know that render_anywhere is a solution for Rails 3.x apps, but I am working in Rails 2.3.11
Thoughts?
I have an old app that I had to do something similar (but made use of polymorphic_path and polymorphic_url) in a model.
The following includes gave me access to url_for and polymorphic_path etc.
include ActionView::Helpers::UrlHelper
include ActionView::Helpers::TagHelper
include ActionController::PolymorphicRoutes
include ActionController::UrlWriter
I have a problem with a Rails 2.3.8 application. I'm using rails i18n to make the site in different languages. Everything works perfect, everywhere, except one place.
After successful signup, I do:
flash[:notice] = t 'path.to.locale.key'
Just as I do everywhere else.
But that renders the following:
translation missing: 'locale.path.to.locale.key' not found
It seems it's not loading the current locale (or else it will say 'en', or 'es', or whatever instead of 'locale').
Any idea that could be causing this?
Thanks
Maybe you overwrite it somewhere down that yml file. Maybe you did too many nesting. Maybe that key has subkeys.
Delete everything from that locale.yml and place only that message and see if it works.
The problem you are having happens to me every now and then, and it's always something I messed up in yml file.
Try setting a default locale in your ApplicationController, for example with a before_filter:
I18n.locale = params[:locale] || 'en'
Well, this happened to me in mailer classes after I upgraded to Rails 4.1. It was working correctly on Rails 3 and there was no change on yml files. Somehow i18n did not see the default locale.
So I've added this line on mailer class to fix out.
I18n.locale = I18n.default_locale
class ProviderMailer < ActionMailer::Base
include Resque::Mailer
default from: APP_CONFIG.mailer.from
def registration_email(provider)
#provider = provider
I18n.locale = I18n.default_locale
#provider_url = "#{APP_CONFIG.base_url}/hizmetsgl/#{provider['_id']}"
#howto_url = "#{APP_CONFIG.base_url}/hizmetverenler"
mail(to: provider["business_email"], subject: t('provider_mailer.registration_email.subject'))
end
end