Locale not working when called from a rake task - ruby-on-rails

I have a Rails app (2.3.8) where I send emails using ActionMailer from my Controllers, with no problems.
However, I´ve created a rake task to be called from a Cronjob (in Heroku). When those emails are sent, no locale transformations in my dates are made.
I´ve googled to find any kind of solution, but couldn´t.
Anyone can help me?
Thanks.
Here is the code:
cron.rake:
desc 'This task is called by the Heroku cron add-on'
task :cron => :environment do
puts 'Sending diary...'
hollydays = [6,0] #weekend
unless hollydays.member?(Time.zone.now.wday) #if is NOT a weekend
User.all.each do |user|
user.deliver_task_diary
end
end
puts 'done.'
end
user model method:
def deliver_task_diary
TaskMailer.deliver_task_diary(self)
end
the method in TaskMailer model:
def task_diary(user)
next_five_tasks = user.next_five_tasks
last_five_tasks = user.last_five_tasks
recipients "#{user.name} <#{user.email}>"
from "My site <no_reply#mysite.com>"
subject "Your daily tasks."
sent_on Time.zone.now
body :user => user, :next_five_tasks => next_five_tasks, :last_five_tasks => last_five_tasks
end
part of my email template that doesn´t locale:
<%=l task.estimated_delivery_date, :format => :short %>

Solved.
I don´t know if it´s the best way, but I´ve just declared the locale at the very beging of the email html template:
<% I18n.locale = "pt-BR" %>

Related

Rails, Capybara - click_link on remote links doesnt work

I'm using Capybara to test my project. But i have a problem.
I have some remote forms on my project. They add records via ajax. When i'm testing with capybara it works well on development environment. It visits the page, fills in the form and submits. Booom, record has been added and test didnt fail.
But when i run rspec with test environments i'm getting unknown format exception.
1) add new address user adds new address
Failure/Error: find("input[value='Adres Ekle']").click
ActionController::UnknownFormat:
Account::AddressesController#create is missing a template for this request format and variant.
request.formats: ["text/html"]
request.variant: []
# ./spec/features/user_add_new_address_spec.rb:28:in `block (2 levels) in <top (required)>'
I've also tried to respond via js from controller like;
def create
request.format = :js
end
Then it returns;
1) add new address user adds new address
Failure/Error: find("input[value='Adres Ekle']").click
ActionController::UnknownFormat:
Account::AddressesController#create is missing a template for this request format and variant.
request.formats: ["text/javascript"]
request.variant: []
# ./spec/features/user_add_new_address_spec.rb:28:in `block (2 levels) in <top (required)>'
And my scenario if u want more info;
scenario 'user adds new address' do
expect(page).to have_content 'Kayıtlı Adreslerim'
find("a[title='Adres Ekle']").click
expect(page).to have_content 'Yeni Adres Ekle'
expect(page).to have_content 'Adres Başlığı'
fill_in 'address[name]', with:'Izmir Ofisi'
select('Izmir', :from => 'address[city_id]')
fill_in 'address[address]', with: 'Lorem ipsum dolor sit amet.'
find("input[value='Adres Ekle']").click # It submits remote: true form.
expect(page).to have_content 'Success!'
end
PS: my create action doesnt render something like that.
its like;
def create
#new_address = Address.new
#address = #current_account.addresses.new(address_params)
if #address.save
#check = true
else
#check = false
end
end
it renders: create.js.erb
<% if #check %>
if($('.addresses').length) {
$('.addresses').append('<%= j(render('account/addresses/address', address: #address)) %>');
}
if($('#did-addresses').length){
$('#did-addresses').append("<%= "<option selected='true' value='#{#address.id}'>#{#address.name}</option>".html_safe %>").selectpicker('refresh');
}
$('#new-address').html('<%= j(render('account/addresses/form', new_address: #new_address)) %>');
swal({
type: 'success',
title: "<%= t('response.success') %>",
text: "<%= t('flash.actions.create.notice', resource_name: Address.model_name.human) %>",
timer: 2000
});
quickview.close('#new-address');
<% else %>
<% #address.errors.each do |error| %>
<% end %>
<% end %>
$('.preloader').fadeOut();
I was facing the same case in rails 6 but I fixed it be adding js: true to the scenario and it automatically worked well.
scenario 'Should delete the feature', js: true do
# Your logic
# Your expectations
end
Since copying your development config over your test config fixed your issue, it sounds like you probably an error in one of your JS files. Normally in the test and production environment all of your JS assets get concatenated into one file which means an error in any one of them can prevent the code in the others from being executed. In the development environment each JS file is loaded separately which means an error in any file can only affect the rest of the code in that file. Check your the console in your browser for any JS errors when going to the page in question and fix them.

NoMethodError: undefined method `const_defined?' when referring to class methods

I am building an email sending system into an already fairly complex rails app.
From a controller I'm trying to call a method that builds an email and then delivers it.
In controller:
response_for :create, :update do
estimate = current_object.estimate.reload
flash[:success] = "Tier Save Successful. "
flash[:success] += send_estimate_email if estimate.verify && estimate.tiers.select{|t| !t.verified?}.empty?
flash[:notice] = "This service bundle was changed for a previously verified service bundle. Please re-verify after changes are complete" if current_object.auto_unverified
redirect_to [current_object.estimate]
end
def send_estimate_email
return "" if current_object.estimate.requestor_email.blank? || !current_object.estimate.requestor_notified_at.blank?
begin
estimate = current_object.estimate
host = request.host_with_port
binding.pry
success = EstimateEmailer.deliver_verification_complete(estimate, host)
current_object.estimate.notes.create!(:user_id => User.find(:first, :conditions => {:user_type_id => UserType::ROOT.id}).id, :title => "Verification Complete Email Sent", :body => "TO: #{success.to}\nSUBJECT: #{success.subject}\nBODY: #{success.body}")
rescue Exception => e
logger.warn(e)
success = false
end
if success
current_object.estimate.update_attribute(:requestor_notified_at, Time.now)
current_object.estimate.notes.create!(:title => "Auto-email sent to requestor", :body => "TO: #{success.to}\nSUBJECT: #{success.subject}\nBODY: #{success.body}", :user_id => current_user.id)
return "Automatic estimate email was successfully sent to #{current_object.estimate.requestor_email}"
else
return "However, automatic estimate email could not be sent due to an error"
end
end
I don't think there's anything wrong with the email code itself, but for some reason I get this error on the EstimateEmailer.deliver_verification_complete(estimate, host) call:
NoMethodError: undefined method `const_defined?' for "estimate":String
setting a breakpoint in the controller before the EstimateEmailer call I notice that I get the error whenever I try to refer to other classes. Just calling EstimateEmailer or any other class name returns the same error.
I've run into issues with undefined method const_defined? in the past. I'm guessing the issue isn't specific to emailing, but I haven't the slightest idea where to begin debugging.
def verification_complete(estimate, host)
request_id = estimate.integration_transactions.empty? ? "Internal ID #{estimate.id}" : estimate.integration_transactions.last.source_id
#estimate = estimate
#estimate_url = public_estimate_url(estimate.public_id, :host => host, :protocol => 'https')
mail(
subject: "Ref ##{estimate.project_code} Application Hosting Estimate Available for Review: #{request_id}",
to: [estimate.requestor_email, estimate.project_manager_email].reject{|email| email.blank? }.join(','),
from: SUPPORT_ADDRESS
)
end
You're using make_resourceful which has an incompatibility with current versions of ActiveSupport. I've just lodged a PR that addresses it: https://github.com/hcatlin/make_resourceful/pull/16.
Alternatively, you can point to the remote branch in your Gemfile:
gem 'make_resourceful', github: 'carpodaster/make_resourceful', branch: 'fix/incompatibility-with-active-support-dependencies'
I assume this problem only occurs in your development environment, right? In that case, you should be able to avoid it by setting config.eager_load = true in config/environments/development.rb.

ActionMailer::Base::NullMail when trying exception_notification in development

I'd like to add the exception_notification gem to our app, however, this happens when I try to manually trigger a mail:
exception
# => #<ZeroDivisionError: divided by 0>
ExceptionNotifier::Notifier.exception_notification(request.env, exception)
# => #<ActionMailer::Base::NullMail:0x007fa81bc7c610>
ExceptionNotifier::Notifier.background_exception_notification(exception)
# => #<ActionMailer::Base::NullMail:0x007fa81bf58190>
In the above example, the console is at a breakpoint inside rescue_from Exception in the ApplicationController after a deliberate 1/0 in some controller.
I'm using delayed_job as well, but - no surprise - ExceptionNotifier::Notifier.background_exception_notification(exception).deliver does not spool anything.
I've already set config.consider_all_requests_local = false in development, but still exception_notification instantiates NullMail. In other parts of the app, mailers work just fine and use sendmail.
Any ideas what I'm doing wrong here? Thanks for your help!
Likely you are using an old version of the ExceptionNotifier and a newer version of ActiveMailer::Base. Not calling the mail command within the email functionality will result in the ActionMailer::Base::NullMail instance returned rather than a Mail instance.
From documentation:
class Notifier < ActionMailer::Base
default :from => 'no-reply#example.com',
:return_path => 'system#example.com'
def welcome(recipient)
#account = recipient
mail(:to => recipient.email_address_with_name,
:bcc => ["bcc#example.com", "Order Watcher <watcher#example.com>"])
end
end
I had my tests / rspec returning NullMail objects. the solution was simple, my code was:
def my_mail(foo)
mail(
to: to,
from: from,
subject: #sample_item.campaign_market.campaign.translation_for(language_id, 'sample_item_mailer.request_review.subject'),
content_type: "text/html"
)
#sample_item.update_attributes!({feedback_requested: true, review_requested_at: Time.now})
TrackingService::Event.new(#user, #user.market, 'sample_items', "request_review_email #{#sample_item.id}").call()
end
what's not immediately clear from the ruby docs is that you need to return the mail function,not just execute it. If you need to do something after building the mail object make sure you return the mail at the end. like so:
def my_mail(foo)
m = mail(
to: to,
from: from,
subject: #sample_item.campaign_market.campaign.translation_for(language_id, 'sample_item_mailer.request_review.subject'),
content_type: "text/html"
)
#sample_item.update_attributes!({feedback_requested: true, review_requested_at: Time.now})
TrackingService::Event.new(#user, #user.market, 'sample_items', "request_review_email #{#sample_item.id}").call()
return m
end

I18n: How to check if a translation key/value pairs is missing?

I am using Ruby on Rails 3.1.0 and the I18n gem. I (am implementing a plugin and) I would like to check at runtime if the I18n is missing a translation key/value pairs and, if so, to use a custom string. That is, I have:
validates :link_url,
:format => {
:with => REGEX,
:message => I18n.t(
'custom_invalid_format',
:scope => 'activerecord.errors.messages'
)
}
If in the .yml file there is not the following code
activerecord:
errors:
messages:
custom_invalid_format: This is the test error message 1
I would like to use the This is the test error message 2. Is it possible? If so, how can I make that?
BTW: For performance reasons, is it advisable to check at runtime if the translation key/value pairs is present?
You could pass a :default parameter to I18n.t:
I18n.t :missing, :default => 'Not here'
# => 'Not here'
You can read more about it here.
I just had the same question and I want to compute an automatic string in case the translation is missing. If I use the :default option I have to compute the automatic string every time even when the translation is not missing. So I searched for another solution.
You can add the option :raise => true or use I18n.translate! instead of I18n.translate. If no translation can be found an exception is raised.
begin
I18n.translate!('this.key.should.be.translated', :raise => true)
rescue I18n::MissingTranslationData
do_some_resource_eating_text_generation_here
end
I don't know how to this at runtime but you can use rake to find it out. You'll have create your own rake task for that. Here's one:
namespace :i18n do
desc "Find and list translation keys that do not exist in all locales"
task :missing_keys => :environment do
def collect_keys(scope, translations)
full_keys = []
translations.to_a.each do |key, translations|
new_scope = scope.dup << key
if translations.is_a?(Hash)
full_keys += collect_keys(new_scope, translations)
else
full_keys << new_scope.join('.')
end
end
return full_keys
end
# Make sure we've loaded the translations
I18n.backend.send(:init_translations)
puts "#{I18n.available_locales.size} #{I18n.available_locales.size == 1 ? 'locale' : 'locales'} available: #{I18n.available_locales.to_sentence}"
# Get all keys from all locales
all_keys = I18n.backend.send(:translations).collect do |check_locale, translations|
collect_keys([], translations).sort
end.flatten.uniq
puts "#{all_keys.size} #{all_keys.size == 1 ? 'unique key' : 'unique keys'} found."
missing_keys = {}
all_keys.each do |key|
I18n.available_locales.each do |locale|
I18n.locale = locale
begin
result = I18n.translate(key, :raise => true)
rescue I18n::MissingInterpolationArgument
# noop
rescue I18n::MissingTranslationData
if missing_keys[key]
missing_keys[key] << locale
else
missing_keys[key] = [locale]
end
end
end
end
puts "#{missing_keys.size} #{missing_keys.size == 1 ? 'key is missing' : 'keys are missing'} from one or more locales:"
missing_keys.keys.sort.each do |key|
puts "'#{key}': Missing from #{missing_keys[key].join(', ')}"
end
end
end
put the given in a .rake file in your lib/tasks directory and execute:
rake i18n:missing_keys
Information source is here and code on github here.
If you wish to pass variable to the message like This is the test error message {variable}
This is possible using variable in language file like below.
# app/views/home/index.html.erb
<%=t 'greet_username', :user => "Bill", :message => "Goodbye" %>
# config/locales/en.yml
en:
greet_username: "%{message}, %{user}!"
More description you can find here.

Why is this RSpec test failing?

I'm in the process of learning Ruby on Rails, so treat me like a total neophyte, because I am.
I've got a User model with some associated RSpec tests, and the following test fails:
require 'spec_helper'
describe User do
it 'should require a password' do
User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''}).should_not be_valid
end
end
The relevant part of the User model looks like this:
class User < ActiveRecord::Base
...
validates :password, :presence => true,
:confirmation => true,
:length => { :minimum => 6 }
...
end
Here's the catch: if I run User.new(...).valid? from a Rails console using the arguments above, it returns false as expected and shows the correct errors (password is blank).
I was using spork/autotest and I restarted both to no avail, but this test also fails even running it directly with rspec. What am I doing wrong here?
EDIT
I tried a few more things with the test. This fails:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.should_not be_valid
So does this:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.valid?
u.errors.should_not be_empty
This passes, confirming that :password is indeed blank:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.password.should == ''
So, it's actually spork that is causing the problem. You can turn caching off, so that it won't need restarting every time :
http://ablogaboutcode.com/2011/05/09/spork-testing-tip-caching-classes
I think this is what happens :
ruby-1.9.2-p180 :020 > u = User.new
=> #<User id: nil, email: ...
ruby-1.9.2-p180 :021 > u.errors
=> {}
ruby-1.9.2-p180 :022 > u.save
=> false
ruby-1.9.2-p180 :023 > u.errors
=> {:email=>["can't be blank", "can't be blank"], ...}
In short, if you change new to create, it will work :) I think that this happens because the matcher be_valid checks on the model validation errors. There can be a deeper explanation, but i think that if you use create instead of new, it will work.
EDIT : I have a be_valid_verbose version that might help. Just create a 'be_valid_verbose.rb' file in your rspec/custom_matchers folder, and inside it write :
RSpec::Matchers.define :be_valid_verbose do
match do |model|
model.valid?
end
failure_message_for_should do |model|
"#{model.class} expected to be valid but had errors:n #{model.errors.full_messages.join("n ")}"
end
failure_message_for_should_not do |model|
"#{model.class} expected to have errors, but it did not"
end
description do
"be valid"
end
end
Now check against be_valid_verbose instead of be_valid. It will hopefully present you with some more information on what is happening in your case.
As I feared, the answer was stupidity. This was a spork problem. I thought I had killed the existing process and was running rspec independently, but I later found the spork process still running in a different shell, and rspec had been connecting to it all along. Restarting spork (or killing it entirely) and re-running the tests fixed the problem.
I found this particularly deceptive in that rspec continually updated the test output to reflect the fact that it was aware of my test changes, so it appeared to me that it was running against up-to-date code. Now I'm left to wonder what the real utility of spork is, since apparently I can't trust that it's actually running the right tests correctly.

Resources