I have a Rails 5 app in which I use Globalize for localization. I'm currently having an issue where I can't save new objects if they don't have any translations.
My model looks like this:
# Product.rb
translates :description, :fallbacks_for_empty_translations => true
has_many :translations
accepts_nested_attributes_for :translations
# ProductTranslation.rb
belongs_to :product, optional: true
My database schema looks for my product_translations looks like this:
t.integer "product_id", null: false
t.string "locale", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "description"
t.index ["locale"], name: "index_product_translations_on_locale"
t.index ["product_id"], name: "index_product_translations_on_product_id"
When I try to save new products I currently get this error:
Unable to save product with id = got these validation errors {:"translations.globalized_model"=>["translation missing: sv.activerecord.errors.models.product/translation.attributes.globalized_model.required"]}
Any ideas on what I can do to make it work?
Related
So I am currently assigned a task in Ruby which I have never used before and I've run into a very strange problem. I have this migration for a model message, which has an index on chat_id and number.
class CreateMessages < ActiveRecord::Migration[5.2]
def change
create_table :messages do |t|
t.references :chat, foreign_key: true, null: false
t.integer :number, null: false
t.string :body
#t.index [:chat_id, :number] doesn't work
t.timestamps
end
#add_index :messages, [:chat_id, :number] #doesn't work either
end
end
The end schema of both those migrations when running rails db:migrate is this
create_table "messages", force: :cascade do |t|
t.integer "chat_id", null: false
t.integer "number", null: false
t.string "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["chat_id", "number"], name: "index_messages_on_chat_id_and_number"
t.index ["chat_id"], name: "index_messages_on_chat_id"
end
Obviously, the second created index is completely useless. How do I prevent this from occuring and create only one index when migrating?
Ruby 2.7.6
Rails 5.2.8.1
This line is adding the index you wish to remove. It accepts an index parameter which defaults to true, change it to:
t.references :chat, foreign_key: true, null: false, index: false
This question was discussed numerous times, however I run into an issue that I could not find an answer to.
I am building a login system where one Member(:class) "bails for" a new Member. Internally, they are referenced as "member" and "candidate" respectively. Until the member has accepted the bail, a BailRequest(:class) is listed in the according table.
According to the rails guide, the right way to tell rails about the class refering to would be
class BailRequest < ApplicationRecord
belongs_to :candidate, class_name: "Member"
belongs_to :member
end
where class_name: "Member" should tell rails that BailRequest.candidate is of class: Member. The very same approach worked in the member class flawlessly
class Member < ApplicationRecord
belongs_to :bail, class_name: "Member", optional: true
has_many :associates, class_name: "Member", foreign_key: "bail_id"
end
However, this time when I want to save a BailRequest to the database, I get an ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: main.candidates.
It looks like ActiveRecord is expecting a table called "candidates" here. What am I missing?
$ rails -v
Rails 5.2.1
[$ ruby -v
ruby 2.3.1p112 (2016-04-26) [i386-linux-gnu]]
The schema.rb shows the following after migration
create_table "bail_requests", force: :cascade do |t|
t.integer "candidate_id"
t.integer "member_id"
t.string "message", limit: 100
t.boolean "accepted"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["candidate_id"], name: "index_bail_requests_on_candidate_id", unique: true
t.index ["member_id"], name: "index_bail_requests_on_member_id"
end
create_table "members", force: :cascade do |t|
t.string "email", limit: 50, null: false
t.string "password_digest", null: false
t.integer "bail_id"
t.string "username", limit: 50
t.string "first_name", limit: 50
t.string "last_name", limit: 50
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_members_on_email", unique: true
t.index ["username"], name: "index_members_on_username", unique: true
end
Logic:
When a Member m registers, m has to reference a Member n by name.
m.bail equals nil/null and a BailRequest br is created with
br.member = n and br.candidate = m
If member accepts the bail, br.accepted is set to true. m.bail is set to n and m is in n.associates
In the migration file, I changed
t.references :candidate, index: {:unique=>true}
to
t.integer :candidate_id, index: {:unique=>true}, foreign_key: true
and rerun the migration. It is now working on the rails console. Thanks to arieljuod for your effort.
I have issue with associations with search
class Manufacturer < ApplicationRecord
has_many :translations, class_name: 'ManufacturerTranslation', dependent: :destroy
def self.search(query)
q = query.to_s.parameterize.gsub('-',' ').split
joins(:translations).where("lower(name) LIKE ?", "%#{q}%")
end
and
class ManufacturerTranslation < ApplicationRecord
belongs_to :manufacturer
end
so when i have tried to do search and call translations on it
Manufacturer.search('fra').last.translations
it gives me only translations with name which include fra, not all of translations
so i have 6 translations in total for this manufacturer
but after search a get only 2
database schema
create_table "manufacturer_translations" do |t|
t.integer "manufacturer_id"
t.string "locale"
t.string "name"
t.string "image_source_url"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["manufacturer_id"], name: "index_manufacturer_translations_on_manufacturer_id"
t.index ["name"], name: "index_manufacturer_translations_on_name"
end
create_table "manufacturers", do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "deleted", default: false
end
As you are splitting the string you have to loop through all the entities to search them. And you also have to downcase the results. try out the following code:
def self.search(query)
q = query.to_s.parameterize.gsub('-',' ').split
conditions = ''
q.each do |qu|
conditions = "#{conditions} OR " if conditions.present?
conditions = "#{condidtions} lower(manufacturers.name) LIKE %#{qu.downcase}%"
end
joins(:translations).where(conditions)
end
Assuming you follow Rails conventions I'd suggest you to replace this
joins(:translations).where("lower(name) LIKE ?", "%#{q}%")
with
joins(:translations).where("lower(manufacturers.name) LIKE ?", "%#{q}%")
May be needed to play with quotations
I have a table mobility_string_translations, but I do not understand how to get to it.
Now I have three records. Two records in German and one in Spanish. I want to get only those records that are in German.
this not working:
all_de_posts = Post.i18n.find_by(locale: :de)
First of all you may have a column.(Lets say title.)
On your model post.rb you will have something like this:
class Post < ApplicationRecord
extend Mobility
translates :title, type: :string, locale_accessors: [:en, :de]
end
The type is important in order to get the :de records(or the :en).
At schema.rb wou will see a table mobility_string_translations
create_table "mobility_string_translations", force: :cascade do |t|
t.string "locale", null: false
t.string "key", null: false
t.string "value"
t.integer "translatable_id", null: false
t.string "translatable_type", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["translatable_id", "translatable_type", "key"], name: "index_mobility_string_translations_on_translatable_attribute"
t.index ["translatable_id", "translatable_type", "locale", "key"], name: "index_mobility_string_translations_on_keys", unique: true
t.index ["translatable_type", "key", "value", "locale"], name: "index_mobility_string_translations_on_query_keys"
end
Well now at your console find your records with locale: :de
irb:> Post.all
irb:> Mobility::ActiveRecord::StringTranslation.where(locale: :de)
As you can see at your schema.rb --> "mobility_string_translations" you can play around with your columns in order to find exactly what you want.
I am relatively new to RoR.
This works nicely:
<td><%= collection_select :competitions_members, :member_id, Member.all, :id, :first_name %></td>
This one picks no value (actually all such calls to tables with translations):
<td><%= collection_select :competitions_members, :tull_id, Tull.all, :id, :name %></td>
seeded data in competitions_members table
Member can be involved in many competition. Basically I have N:M relationship between members and competitions via competitions_members table.
Tull is a dictionary. Value to be set during the process of assigning members to a competition.
Data model classes:
class Member < ApplicationRecord
has_and_belongs_to_many :competitions
end
class Competition < ApplicationRecord
has_and_belongs_to_many :members
end
class CompetitionsMember < ApplicationRecord
end
Tull table has also translations in separate table.
class Tull < ApplicationRecord
translates :name
has_many :competitions_members
# separate different localizations of the record
def cache_key
super + '-' + Globalize.locale.to_s
end
end
Relevant schema.db excerpt
create_table "members", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "competitions", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "competitions_members", force: :cascade do |t|
t.integer "member_id"
t.integer "competition_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "tull_id"
t.index ["tull_id"], name: "index_competitions_members_on_tull_id"
end
create_table "tull_translations", force: :cascade do |t|
t.integer "tull_id", null: false
t.string "locale", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.index ["locale"], name: "index_tull_translations_on_locale"
t.index ["tull_id"], name: "index_tull_translations_on_tull_id"
end
create_table "tulls", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Any help apreciated. I just realized this might be connected with translated tables somehow.
class Tull < ApplicationRecord
has_many :translations
translates :name, :fallbacks_for_empty_translations => true
attr_accessible :translations_attributes
end
Try to execute below code in rails console:
Tull.first.translations - If this gives you translation records that means the associations are correct.
Now check at view side, how would you generate attributes for multilingual stuffs. I would suggest to use globalize_accessors.
Please send me the codebase.