class Mobility::Backends::ActiveRecord::Table
Implements the {Mobility::Backends::Table} backend for ActiveRecord
models.
To generate a translation table for a model Post
, you can use the included mobility:translations
generator:
rails generate mobility:translations post title:string content:text
This will create a migration which can be run to create the translation table. If the translation table already exists, it will create a migration adding columns to that table.
@example Model with table backend
class Post < ApplicationRecord extend Mobility translates :title, backend: :table end post = Post.create(title: "foo") #<Post:0x00... id: 1> post.title #=> "foo" post.translations #=> [#<Post::Translation:0x00... # id: 1, # locale: "en", # post_id: 1, # title: "foo">] Post::Translation.first #=> #<Post::Translation:0x00... # id: 1, # locale: "en", # post_id: 1, # title: "foo">
@example Model with multiple translation tables
class Post < ActiveRecord::Base extend Mobility translates :title, backend: :table, table_name: :post_title_translations, association_name: :title_translations translates :content, backend: :table, table_name: :post_content_translations, association_name: :content_translations end post = Post.create(title: "foo", content: "bar") #<Post:0x00... id: 1> post.title #=> "foo" post.content #=> "bar" post.title_translations #=> [#<Post::TitleTranslation:0x00... # id: 1, # locale: "en", # post_id: 1, # title: "foo">] post.content_translations #=> [#<Post::ContentTranslation:0x00... # id: 1, # locale: "en", # post_id: 1, # content: "bar">] Post::TitleTranslation.first #=> #<Post::TitleTranslation:0x00... # id: 1, # locale: "en", # post_id: 1, # title: "foo"> Post::ContentTranslation.first #=> #<Post::ContentTranslation:0x00... # id: 1, # locale: "en", # post_id: 1, # title: "bar">
Public Class Methods
Joins translations using either INNER/OUTER join appropriate to the query. @param [ActiveRecord::Relation] relation Relation to scope @param [Object] predicate Arel predicate @param [Symbol] locale (Mobility.locale
) Locale @option [Boolean] invert @return [ActiveRecord::Relation] relation Relation with joins applied (if needed)
# File lib/mobility/backends/active_record/table.rb, line 131 def apply_scope(relation, predicate, locale = Mobility.locale, invert: false) visitor = Visitor.new(self, locale) if join_type = visitor.accept(predicate) join_type &&= Visitor::INNER_JOIN if invert join_translations(relation, locale, join_type) else relation end end
@param [String] attr Attribute name @param [Symbol] _locale Locale @return [Mobility::Plugins::Arel::Attribute] Arel node for column on translation table
# File lib/mobility/backends/active_record/table.rb, line 119 def build_node(attr, locale) aliased_table = model_class.const_get(subclass_name).arel_table.alias(table_alias(locale)) Plugins::Arel::Attribute.new(aliased_table, attr, locale, self) end
@!group Backend
Configuration @option options [Symbol] association_name (:translations)
Name of association method
@option options [Symbol] table_name Name of translation table @option options [Symbol] foreign_key Name of foreign key @option options [Symbol] subclass_name (:Translation) Name of subclass
to append to model class to generate translation class
# File lib/mobility/backends/active_record/table.rb, line 102 def configure(options) table_name = model_class.table_name options[:table_name] ||= "#{table_name.singularize}_translations" options[:foreign_key] ||= table_name.downcase.singularize.camelize.foreign_key if (association_name = options[:association_name]).present? options[:subclass_name] ||= association_name.to_s.singularize.camelize.freeze else options[:association_name] = :translations options[:subclass_name] ||= :Translation end %i[foreign_key association_name subclass_name table_name].each { |key| options[key] = options[key].to_sym } end
Private Class Methods
# File lib/mobility/backends/active_record/table.rb, line 152 def already_joined?(relation, locale, join_type) if join = get_join(relation, locale) return true if (join_type == Visitor::OUTER_JOIN) || (Visitor::INNER_JOIN === join) relation.joins_values -= [join] end false end
# File lib/mobility/backends/active_record/table.rb, line 160 def get_join(relation, locale) relation.joins_values.find { |v| (::Arel::Nodes::Join === v) && (v.left.name == table_alias(locale).to_s) } end
# File lib/mobility/backends/active_record/table.rb, line 143 def join_translations(relation, locale, join_type) return relation if already_joined?(relation, locale, join_type) m = model_class.arel_table t = model_class.const_get(subclass_name).arel_table.alias(table_alias(locale)) relation.joins(m.join(t, join_type). on(t[foreign_key].eq(m[:id]). and(t[:locale].eq(locale))).join_sources) end
Public Instance Methods
Returns translation for a given locale, or builds one if none is present. @param [Symbol] locale
# File lib/mobility/backends/active_record/table.rb, line 291 def translation_for(locale, **) translation = translations.in_locale(locale) translation ||= translations.build(locale: locale) translation end