in my Rails 3.2.2 app I'm trying to use i18n but something is not working correctly.
In fact the "t" method does not work, only "i18n.t" works.
So, for example:
t(:login)
=> login
Instead:
i18n.t(:login)
=> Provide the necessary login info
Can you help me to figure out what I'm doing wrong?
Thanks,
Augusto
UPDATE
I used pry to show the source for the t helper and got this:
From: /Users/phishman/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.2.2/lib/action_view/helpers/translation_helper.rb # line 46:
Number of lines: 16
Owner: ActionView::Helpers::TranslationHelper
Visibility: public
def translate(key, options = {})
options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
if html_safe_translation_key?(key)
html_safe_options = options.dup
options.except(*I18n::RESERVED_KEYS).each do |name, value|
unless name == :count && value.is_a?(Numeric)
html_safe_options[name] = ERB::Util.html_escape(value.to_s)
end
end
translation = I18n.translate(scope_key_by_partial(key), html_safe_options)
translation.respond_to?(:html_safe) ? translation.html_safe : translation
else
I18n.translate(scope_key_by_partial(key), options)
end
end
3] pry(main)> show-source helper.t
From: /Users/phishman/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.2.2/lib/action_view/helpers/translation_helper.rb # line 46:
Number of lines: 16
Owner: ActionView::Helpers::TranslationHelper
Visibility: public
def translate(key, options = {})
options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
if html_safe_translation_key?(key)
html_safe_options = options.dup
options.except(*I18n::RESERVED_KEYS).each do |name, value|
unless name == :count && value.is_a?(Numeric)
html_safe_options[name] = ERB::Util.html_escape(value.to_s)
end
end
translation = I18n.translate(scope_key_by_partial(key), html_safe_options)
translation.respond_to?(:html_safe) ? translation.html_safe : translation
else
I18n.translate(scope_key_by_partial(key), options)
end
end
the t method is a helper and therefore only available in views and controllers.
If you try to use I18n from models or the rails console, you should use I18n.t
Related
I'm working with redmine and I've installed a plugin for managing mails.
When I try to send a mail I obtain the following error
[ActiveJob] [ActionMailer::DeliveryJob] [uuid] Error performing ActionMailer::DeliveryJob (Job ID: uuid) from Async(mailers) in 41.81ms: NoMethodError (undefined method `each' for #<User:id>):
This is the file that gives me the error
module EncryptMails
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
alias_method :mail_without_relocation, :mail
alias_method :mail, :mail_with_relocation
end
end
module InstanceMethods
# action names to be processed by this plugin
def actions
[
'attachments_added',
'document_added',
'issue_add',
'issue_edit',
'message_posted',
'news_added',
'news_comment_added',
'wiki_content_added',
'wiki_content_updated'
]
end
# dispatched mail method
def mail_with_relocation(headers={}, &block)
# pass unchanged, if action does not match or plugin is inactive
act = Setting.plugin_openpgp['activation']
return mail_without_relocation(headers, &block) if
act == 'none' or not actions.include? #_action_name or
(act == 'project' and not project.try('module_enabled?', 'openpgp'))
# relocate recipients
recipients = relocate_recipients(headers)
header = #_message.header.to_s
# render and deliver encrypted mail
reset(header)
m = mail_without_relocation prepare_headers(
headers, recipients[:encrypted], encrypt = true, sign = true
) do |format|
format.text
end
m.deliver
# render and deliver filtered mail
reset(header)
tpl = #_action_name + '.filtered'
m = mail_without_relocation prepare_headers(
headers, recipients[:filtered], encrypt = false, sign = true
) do |format|
format.text { render tpl }
format.html { render tpl } unless Setting.plain_text_mail?
end
m.deliver
# render unchanged mail (deliverd by calling method)
reset(header)
m = mail_without_relocation prepare_headers(
headers, recipients[:unchanged], encrypt = false, sign = false
) do |format|
format.text
format.html unless Setting.plain_text_mail?
end
m
end
# get project dependent on action and object
def project
case #_action_name
when 'attachments_added'
#attachments.first.project
when 'document_added'
#document.project
when 'issue_add', 'issue_edit'
#issue.project
when 'message_posted'
#message.project
when 'news_added', 'news_comment_added'
#news.project
when 'wiki_content_added', 'wiki_content_updated'
#wiki_content.project
else
nil
end
end
# relocates reciepients (to, cc) of message
def relocate_recipients(headers)
# hash to be returned
recipients = {
:encrypted => {:to => [], :cc => []},
:blocked => {:to => [], :cc => []},
:filtered => {:to => [], :cc => []},
:unchanged => {:to => [], :cc => []},
:lost => {:to => [], :cc => []}
}
# relocation of reciepients
[:to, :cc].each do |field|
headers[field].each do |user|
# encrypted
unless Pgpkey.find_by(user_id: user.id).nil?
recipients[:encrypted][field].push user and next
end
# unencrypted
case Setting.plugin_openpgp['unencrypted_mails']
when 'blocked'
recipients[:blocked][field].push user
when 'filtered'
recipients[:filtered][field].push user
when 'unchanged'
recipients[:unchanged][field].push user
else
recipients[:lost][field].push user
end
end unless headers[field].blank?
end
recipients
end
# resets the mail for sending mails multiple times
def reset(header)
#_mail_was_called = false
#_message = Mail.new
#_message.header header
end
# prepares the headers for different configurations
def prepare_headers(headers, recipients, encrypt, sign)
h = headers.deep_dup
# headers for recipients
h[:to] = recipients[:to]
h[:cc] = recipients[:cc]
# headers for gpg
h[:gpg] = {
encrypt: false,
sign: false
}
# headers for encryption
if encrypt
h[:gpg][:encrypt] = true
# add pgp keys for emails
h[:gpg][:keys] = {}
[:to, :cc].each do |field|
h[field].each do |user|
user_key = Pgpkey.find_by user_id: user.id
unless user_key.nil?
h[:gpg][:keys][user.mail] = user_key.fpr
end
end unless h[field].blank?
end
end
# headers for signature
if sign
server_key = Pgpkey.find_by(:user_id => 0)
unless server_key.nil?
h[:gpg][:sign] = true
h[:gpg][:sign_as] = Setting['mail_from']
h[:gpg][:password] = server_key.secret
end
end
h
end
end
end
The stack of the log tells me that the error is in row 109
# relocation of reciepients
[:to, :cc].each do |field|
I'm not an expert of ruby and rails but I've seen that each is a method of a Ruby array, not a custom one, so I don't understand why I obtain the error.
What I am doing wrong and how can I fix this error?
Are you sure the problem isn't on this line?
h[field].each do |user|
The field there would be :to or :cc so h[field] could be a User instance.
If you want to allow h[:to] or h[:cc] to be a single User or an array of Users, then wrap it in Array():
# relocation of reciepients
[:to, :cc].each do |field|
Array(headers[field]).each do |user|
#^^^^
I'd also move that trailing unless so it doesn't get missed, maybe something like this:
%i[to cc].select { |field| headers[field].present? }.each do |field|
Array(headers[filed]).each do |user|
#...
end
end
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I followed tutorial how to integrate 3rd party api with a ruby on rails but I get an error
undefined method `map' for
{"number"=>12} permitted: false>:ActionController::Parameters
which points to request.rb
query_string = query.map{|k,v| "#{k}=#{v}"}.join("&")
Full code
recipes_controller.rb
class RecipesController < ApplicationController
def index
#tag = query.fetch(:tags, 'all')
#refresh_params = refresh_params
#recipes, #errors = Spoonacular::Recipe.random(query, clear_cache)
end
def show
#recipe = Spoonacular::Recipe.find(params[:id])
end
private
def query
params.permit(:query).fetch(:query, {})
end
def clear_cache
params[:clear_cache].present?
end
def refresh_params
refresh = { clear_cache: true }
refresh.merge!({ query: query }) if query.present?
refresh
end
end
app/services/spoonacular/recipes.rb
module Spoonacular
class Recipe < Base
attr_accessor :aggregate_likes,
:dairy_free,
:gluten_free,
:id,
:image,
:ingredients,
:instructions,
:ready_in_minutes,
:title,
:vegan,
:vegetarian
MAX_LIMIT = 12
CACHE_DEFAULTS = { expires_in: 7.days, force: false }
def self.random(query = {}, clear_cache)
cache = CACHE_DEFAULTS.merge({ force: clear_cache })
response = Spoonacular::Request.where('recipes/random', cache, query.merge({ number: MAX_LIMIT }))
recipes = response.fetch('recipes', []).map { |recipe| Recipe.new(recipe) }
[ recipes, response[:errors] ]
end
def self.find(id)
response = Spoonacular::Request.get("recipes/#{id}/information", CACHE_DEFAULTS)
Recipe.new(response)
end
def initialize(args = {})
super(args)
self.ingredients = parse_ingredients(args)
self.instructions = parse_instructions(args)
end
def parse_ingredients(args = {})
args.fetch("extendedIngredients", []).map { |ingredient| Ingredient.new(ingredient) }
end
def parse_instructions(args = {})
instructions = args.fetch("analyzedInstructions", [])
if instructions.present?
steps = instructions.first.fetch("steps", [])
steps.map { |instruction| Instruction.new(instruction) }
else
[]
end
end
end
end
app/services/spoonacular/base.rb
module Spoonacular
class Base
attr_accessor :errors
def initialize(args = {})
args.each do |name, value|
attr_name = name.to_s.underscore
send("#{attr_name}=", value) if respond_to?("#{attr_name}=")
end
end
end
end
app/services/spoonacular/request.rb
module Spoonacular
class Request
class << self
def where(resource_path, cache, query = {}, options = {})
response, status = get_json(resource_path, cache, query)
status == 200 ? response : errors(response)
end
def get(id, cache)
response, status = get_json(id, cache)
status == 200 ? response : errors(response)
end
def errors(response)
error = { errors: { status: response["status"], message: response["message"] } }
response.merge(error)
end
def get_json(root_path, cache, query = {})
query_string = query.map{|k,v| "#{k}=#{v}"}.join("&")
path = query.empty?? root_path : "#{root_path}?#{query_string}"
response = Rails.cache.fetch(path, expires_in: cache[:expires_in], force: cache[:force]) do
api.get(path)
end
[JSON.parse(response.body), response.status]
end
def api
Connection.api
end
end
end
end
app/services/spoonacular/connection.rb
require 'faraday'
require 'json'
module Spoonacular
class Connection
BASE = 'https://spoonacular-recipe-food-nutrition-v1.p.mashape.com'
def self.api
Faraday.new(url: BASE) do |faraday|
faraday.response :logger
faraday.adapter Faraday.default_adapter
faraday.headers['Content-Type'] = 'application/json'
faraday.headers['X-Mashape-Key'] ='key'
end
end
end
end
Thank you for any help.
You have 2 separate errors here.
uninitialized constant Spoonacular::Recipe::Request
This one you can fix by explicitly setting top-level scope for Request class:
::Request.where(...)
It applies if you keep Request file in app/spoonacular/request.rb. But I suggest to move it to app/services/spoonacular/ where all your other spoonacular related classes are. So in this case you need to encircle class Request in module Spoonacular. After that you can call it like that:
Spoonacular::Request.where(...)
Same goes for class Connection.
SO answer about scope resolution operator
undefined method `map' for {"number"=>12} permitted:
false>:ActionController::Parameters
This one comes from private query method in recipes_controller.rb. params is ActionController::Parameters object and in order to retrieve values from it you need to permit them first:
def query
params.permit(:query).to_h
end
Now it should return Hash object.
Here is detailed answer on SO about that
RubyOnRails Guide about strong params
Decided to JSONify with Redis my site. How do I get will_paginate to work with json?
# games.html.erb
<%= js_will_paginate #games, renderer: BootstrapPagination::Rails, class: 'pagination-sm', previous_label: "←".html_safe, next_label: "→".html_safe, page_links: false %>
This is the error I get:
# undefined method `total_pages' for #<Array:0x007f90ebc05cf0> ln 23 of will_paginate_helper.rb
ln23: will_paginate(collection, options.merge(:renderer => WillPaginateHelper::WillPaginateJSLinkRenderer))
And my will_paginate_helper:
# will_paginate_helper.rb
module WillPaginateHelper
class WillPaginateJSLinkRenderer < BootstrapPagination::Rails
def prepare(collection, options, template)
options[:params] ||= {}
options[:params]['_'] = nil
super(collection, options, template)
end
protected
def link(text, target, attributes = {})
if target.is_a? Fixnum
attributes[:rel] = rel_value(target)
target = url(target)
end
#template.link_to(target, attributes.merge(remote: true)) do
text.to_s.html_safe
end
end
end
def js_will_paginate(collection, options = {})
will_paginate(collection, options.merge(:renderer => WillPaginateHelper::WillPaginateJSLinkRenderer))
end
end
when I play around with the cli below the nomethoderror exception...
>> collection
=> [{"id"=>8199, "start_time"=>nil, "game_date"=>"2016-10-23", ... etc }]
>> collection.first
=> {"id"=>8199, "start_time"=>nil, ... etc
Do I need to convert collection to something will_paginate can work with or do I re-write/override js_will_paginate? Thank you!
Figured it out.
added require 'will_paginate/array' to my will_paginate_helper.rb and then paginated the collection AFTER .to_json, e.g. in my helper (or your controller):
games = Game.order(game_date: :desc).postgame.to_json
#games = Oj.load games
#games = #games.paginate(page: params[:page], per_page: 10)
Works with will_paginate or js_will_paginate just as before.
I'm learning Ruby on Rails and got curious how the params method works. I understand what it does, but how?
Is there a built-in method that takes a hash string like so
"cat[name]"
and translates it to
{ :cat => { :name => <assigned_value> } }
?
I have attempted to write the params method myself but am not sure how to write this functionality in ruby.
The GET parameters are set from ActionDispatch::Request#GET, which extends Rack::Request#GET, which uses Rack::QueryParser#parse_nested_query.
The POST parameters are set from ActionDispatch::Request#POST, which extends Rack::Request#POST, which uses Rack::Multipart#parse_multipart. That splays through several more files in lib/rack/multipart.
Here is a reproduction of the functionality of the method (note: this is NOT how the method works). Helper methods of interest: #array_to_hash and #handle_nested_hash_array
require 'uri'
class Params
def initialize(req, route_params = {})
#params = {}
route_params.keys.each do |key|
handle_nested_hash_array([{key => route_params[key]}])
end
parse_www_encoded_form(req.query_string) if req.query_string
parse_www_encoded_form(req.body) if req.body
end
def [](key)
#params[key.to_sym] || #params[key.to_s]
end
def to_s
#params.to_s
end
class AttributeNotFoundError < ArgumentError; end;
private
def parse_www_encoded_form(www_encoded_form)
params_array = URI::decode_www_form(www_encoded_form).map do |k, v|
[parse_key(k), v]
end
params_array.map! do |sub_array|
array_to_hash(sub_array.flatten)
end
handle_nested_hash_array(params_array)
end
def handle_nested_hash_array(params_array)
params_array.each do |working_hash|
params = #params
while true
if params.keys.include?(working_hash.keys[0])
params = params[working_hash.keys[0]]
working_hash = working_hash[working_hash.keys[0]]
else
break
end
break if !working_hash.values[0].is_a?(Hash)
break if !params.values[0].is_a?(Hash)
end
params.merge!(working_hash)
end
end
def array_to_hash(params_array)
return params_array.join if params_array.length == 1
hash = {}
hash[params_array[0]] = array_to_hash(params_array.drop(1))
hash
end
def parse_key(key)
key.split(/\]\[|\[|\]/)
end
end
I have resource bio and in views and link for add new bio is:
= link_to "Add new bio", [:new, :admin, :bio]
If I put resource :bio to scope like this:
namespace :admin do
scope "/:bio_type", :defaults => {:bio_type => "company"} do
resources :bios
end
end
This doesn't work
= link_to "Add new bio", [:new, :admin, :bio, { bio_type: params[:bio_type] }]
My question is how can I add scoped param to url_for helper? And can rails do this by default?
p.s. new_admin_bio_path({bio_type: params[:bio_type]}) works fine, but it's just curious
I believe you cannot make this with array params to link_to. You have to use polymorphic_path or new_admin_bio_path({bio_type: params[:bio_type]})
The reason is that link_to calls url_for with [:new, :admin, :bio, { bio_type: params[:bio_type] }], which calls polymorphic_path with these params.
Check the source code for url_for and for polymorphic_url.
Notice, that polymorphic_url takes 2 params - record_or_hash_or_array and options, but url_for calls it with one parameter only.
def url_for(options = {})
options ||= {}
case options
when String
options
when Hash
options = options.symbolize_keys.reverse_merge!(:only_path => options[:host].nil?)
super
when :back
controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
else
polymorphic_path(options)
end
end
def polymorphic_path(record_or_hash_or_array, options = {})
polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
end
def polymorphic_url(record_or_hash_or_array, options = {})
if record_or_hash_or_array.kind_of?(Array)
record_or_hash_or_array = record_or_hash_or_array.compact
if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
proxy = record_or_hash_or_array.shift
end
record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
end
record = extract_record(record_or_hash_or_array)
record = convert_to_model(record)
args = Array === record_or_hash_or_array ?
record_or_hash_or_array.dup :
[ record_or_hash_or_array ]
inflection = if options[:action] && options[:action].to_s == "new"
args.pop
:singular
elsif (record.respond_to?(:persisted?) && !record.persisted?)
args.pop
:plural
elsif record.is_a?(Class)
args.pop
:plural
else
:singular
end
args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
url_options = options.except(:action, :routing_type)
unless url_options.empty?
args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
end
args.collect! { |a| convert_to_model(a) }
(proxy || self).send(named_route, *args)
end
So, correct call with the scope option should sound like
polymorphic_path([:new, :admin, :bio], bio_type: params[:bio_type])