take a look into my model and my migration
i only have one attribute to test the globalize3 gem
class Car < ActiveRecord::Base
attr_accessible :name
translates :name
end
my migration looks like the following
class CreateCars < ActiveRecord::Migration
def up
create_table :cars do |t|
t.timestamps
end
Car.create_translation_table! :name => :string
end
def down
Car.drop_translation_table!
drop_table :cars
end
end
and i got the following error while trying to save new car details with the attribute name
ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: locale
i think i am missing some declaration/configuration for globalize3 to access the I18n.locale variable.
btw i am using rails 3.2.3 and ruby 1.9.3p125
just found an workaround to my problem by following this Issue
class Car < ActiveRecord::Base
attr_accessible :name
translates :name
class Translation
attr_accessible :locale
end
end
Shouldn't this be like:
class Car < ActiveRecord::Base
attr_accessible :name, :translations_attributes
translates :name
end
See:
Rails 3.2.3: How to mass assign associated models?
Related
In my domain, many models have names, descriptions, etc. These properties need translations. I know how to represent this in a database. However I struggle finding a way to represent this with Rails.
|-------translations-table--------|
|translation_id|locale|translation|
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
|----------------------modelx-table---------------------|
|id|name_translation_id|description_translation_id|price|
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
|-------modely-table--------|
|id|name_translation_id|date|
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
You do not need to create extra models for translations, yo just need to set up locales in .yml format, check this for further instructions
Update
Ok now I understood your point, you want to add translatable fields on your entities/models, so users can manage those translations through a UI right?, well your approach is correct, however there is a gem called Globalize that does the exact same thing but with more toys, and much more standardized as you want.
This is the solution I eventually came up with:
#Models
class Translation
has_many :translation_records
end
class TranslationRecord
(translation_records.find_by :locale => I18n.locale).text
end
class ModelX
belongs_to :name_translation, :class_name => 'Translation'
belongs_to :description_translation, :class_name => 'Translation'
def name
name_translation.current
end
def description
description_translation.current
end
end
#Migrations
class CreateTranslationRecords < ActiveRecord::Migration[5.0]
def change
create_table :translation_records do |t|
t.references :translation
t.string :locale
t.string :text
end
add_index :translation_records, :locale
end
end
class CreateTranslation < ActiveRecord::Migration[5.0]
def change
create_table :translations do |t|
# only id column
end
end
end
class AddTranslationToModelXs < ActiveRecord::Migration[5.0]
def change
add_reference :model_xs, :name_translation
add_reference :model_xs, :description_translation
end
end
I am running into an error after generating a new scaffold for a table with an existing model: NOT NULL constraint failed: questions.question_text.
This has been covered before, but I have not seen an answer for when there is a set null value, as I have done below.
First, I had already generated a model/migration for this table entitled Questions, which looks like:
..._create_questions.rb
class CreateQuestions < ActiveRecord::Migration
def change
create_table :questions do |t|
t.belongs_to :category, index: true
t.string :question_text, :null => false
t.timestamps
end
end
end
Notice here that I am specifying the null => false. To save some time, I ran a Scaffold command to allow me to enter data into Questions easily:
rails generate scaffold Questions --skip
After restarting the server, I am running into the error above. Since I am directly addressing the null value, I am unclear of why it triggers an error when I reach the block in QuestionsController#create (in other words, when I try to create a Question).
In case it helps, here is my Question.rb model as well:
class Question < ActiveRecord::Base
has_many :quiz_questions
has_many :quizzes, through: :quiz_questions
has_many :answers
belongs_to :category
accepts_nested_attributes_for :answers
end
What am I doing wrong?
If you are using not-null as a form of validation than you would want to add a model validation which enforces this rule as well:
class Question < ActiveRecord::Base
# ...
validates_presence_of :question_text
end
This will prevent database driver level exceptions and provide user feedback.
Since you ran the scaffold generator without any attributes I'm guessing that the params whitelist might be empty as well which would cause the above validation to fail since the input is never actually passed to the initializer.
class QuestionsController < ApplicationController
def create
#question = Question.create(question_params)
# ...
end
private
def question_params
params.require(:question)
.permit(
:category_id,
:question_text
answers_attributes: [:foo, :bar, :baz]
)
end
end
I have a Hash attribute in my model that uses Postgres hstore extention. The problem is that this attribute is converted to String by Rails4. This prevents me to make basic operations such as .each or .map to treat my hash attribute.
Using the Rails console, the Hash is not converted. Typing:
#device.data
#device.data.class
Gives in Rails console:
{"city"=>"London", "owner_name"=>"John"}
Hash
And in the application itself (using the navigator):
"\"city\"=>\"London\","\"owner_name\"=>\"John\"
String
Do you have any idea?
Update:
Here is the model:
class Device < ActiveRecord::Base
belongs_to :company
has_many :records
validates :name, presence: true
end
And the corresponding migration file:
class CreateDevices < ActiveRecord::Migration
def change
create_table :devices do |t|
t.string :name
t.hstore :data
t.integer :company_id
t.timestamps
end
add_index :devices, :name
end
end
Try deleting your tmp folder and restarting all your servers.
rm -rf tmp/*
The problem is that I get this error:
ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: amenity_id
when I run this code:
task import_amenities: :environment do
agent = Mechanize.new
Kindergarten.find_all_by_public(false).each do |k|
p = agent.get(k.uri)
amenities = p.search("td td tr:nth-child(11) td:nth-child(2)").text.split(/(;|,) */)
amenities.each do |a|
am = Amenity.find_or_create_by_name!("#{a}")
k.update_attributes(amenity_id: am.id)
end
end
end
Kindergartens and Amenities are linked through a HABTM relation and are are defined as below:
kindergarten.rb
class Kindergarten < ActiveRecord::Base
attr_accessible :location, :name, :public, :uri, :address, :contact,
:phone, :url, :email, :description,
:password, :password_confirmation, :amenity_ids
has_and_belongs_to_many :amenities
end
amenity.rb
class Amenity < ActiveRecord::Base
attr_accessible :name, :kindergarten_ids
has_and_belongs_to_many :kindergartens
end
and here's the migration for the join table:
class CreateKindergartensAmenitiesJoinTable < ActiveRecord::Migration
def up
create_table :kindergartens_amenities, :id => false do |t|
t.integer :kindergarten_id
t.integer :amenity_id
end
end
end
The error is caused by this line in the rake task:
k.update_attributes(amenity_id: am.id)
Everything seems to work great in the console until I reach the mass assignment. And I think i am really messing something up here since I've never used before HABTM.
Any thoughts?
I couldn't sleep last night because of this bug but I finally found the solution.
there are a few issues in the code and the first one i noticed once i started digging and adding data in the db manually is that the join table is wrongfully named. Fix for that:
class RenameKindergartensAmenitiesTable < ActiveRecord::Migration
def up
rename_table :kindergartens_amenities, :amenities_kindergartens
end
end
apparently the habtm association is has to have stuff put alphabetically in title. source
Second problem is that I assumed that
k.amenity_id = am.id
would add an amenity_id / kindergarten_id for each amenity existing. In fact k.amenity_id does not mean anything (especially in the case of many ids). The solution that worked is this:
amenities.each do |a|
am = Amenity.find_or_create_by_name!("#{a}")
k.update_attributes(amenity_ids: k.amenity_ids.push(am.id))
end
I haven't modified the attr_accessible anywhere
I've been asked to design a multiple language application and I need advice with which is the best approach with Rails.
Basically all the tables have some common fields that doesn't need to
be translated and some others that need translation.
thank you
For this purpose, will approach gem globalize3. Easy to use.
In your gemfile:
gem 'globalize'
Model:
class Article < ActiveRecord::Base
translates :title, :text
end
And migration:
class CreateArticles < ActiveRecord::Migration
def up
create_table :articles do |t|
t.timestamps
end
Article.create_translation_table! :title => :string, :text => :text
end
def down
drop_table :articles
Article.drop_translation_table!
end
end
And run
rake db:migrate