Class: ActiveRecord::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/ext/active_record_ext.rb

Direct Known Subclasses

RailsDbLocalize::Translation

Class Method Summary collapse

Class Method Details

.has_translations(*fields) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/ext/active_record_ext.rb', line 4

def has_translations *fields
  class_eval do

    unless respond_to?(:missing_translation)
        # Register it mostly to remove the translations once you delete an object
        has_many :translations, class_name: "RailsDbLocalize::Translation", as: :resource, dependent: :destroy


        scope :__rails_db_translations_sub_query, lambda{ |lang|
          adapter = Rails.configuration.database_configuration[Rails.env]["adapter"]

          number_of_fields_to_translates = RailsDbLocalize.schema[self.to_s].count

          having_clause = case adapter
          when 'postgresql'
            lambda{ "COUNT(*) == #{number_of_fields_to_translates}::bigint" }
          else
            lambda{ "COUNT(*) == #{number_of_fields_to_translates}" }
          end

          ttable = RailsDbLocalize::Translation.arel_table.name

          # We can unscope, but problems tend to appears
          # with some gems like paranoid.
          table = respond_to?(:klass) ? table.klass : self

          table.select(:id).joins("INNER JOIN \"#{ttable}\"
            ON (\"#{ttable}\".resource_id = \"#{arel_table.name}\".id
            AND \"#{ttable}\".resource_type = '#{to_s}')")
          .group(:resource_type, :resource_id)
          .having(having_clause.call)
          .where(:"rails_db_localize_translations.lang" => lang)
        }

        # Return all rows with missing translation for a selected language.
        scope :missing_translation, lambda{ |lang|
          where("\"#{arel_table.name}\".id NOT IN (#{__rails_db_translations_sub_query(lang).to_sql})")
        }

        # Return all rows with translation OK for a selected language.
        scope :having_translation, lambda{ |lang|
          where("\"#{arel_table.name}\".id IN (#{__rails_db_translations_sub_query(lang).to_sql})")
        }

        def self.preload_translations
          RailsDbLocalize::TranslationCache.instance.prefetch_collections(self)
          self
        end
      end


    fields.each do |field|
      # Add a marker to the schema of the application translations.
      RailsDbLocalize::add_to_schema(self, field)

      # Not sure if I would have to put dependent: :destroy here.
      self.has_many :"#{field}_translations", -> { where(field: field)  }, as: :resource

      # Making the magic happends.
      # I should really learn how to use the Reflection helpers in ActiveRecord, because
      # ruby eval is not the most readable stuff... :o)
      self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
        def #{field}_translated_exists?(lang=nil)
          lang ||= I18n.locale
          !!RailsDbLocalize::TranslationCache.instance.get_translation_for(self.class, self.id, "#{field}", lang, nil )
        end

        def #{field}_translated (lang=nil)
          lang ||= I18n.locale
          RailsDbLocalize::TranslationCache.instance.get_translation_for(self.class, self.id, "#{field}", lang, self.#{field} )
        end

        def #{field}_translated= args
          if args.is_a?(Array)
            value, lang = args
          else
            value = args
            lang = I18n.locale
          end

          if self.id
            translated = RailsDbLocalize::Translation.where(
              resource_type: self.class.to_s, resource_id: self.id,  field: "#{field}", lang: lang
            ).first_or_create

            translated.content = value

            translated.save!
          else
            translations.build field: "#{field}", lang: lang, content: value
          end
        end
      RUBY
    end

  end

end