Class: SimpleEnum::Multiple::Accessors::JoinTableAccessor

Inherits:
MultipleAccessor
  • Object
show all
Defined in:
lib/simple_enum/multiple/accessors/join_table_accessor.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from MultipleAccessor

#fetch_keys, #fetch_values, #filter_keys, #initialize, #read, #selected?, #write

Constructor Details

This class inherits a constructor from SimpleEnum::Multiple::Accessors::MultipleAccessor

Instance Attribute Details

#foreign_keyObject

Returns the value of attribute foreign_key.



7
8
9
# File 'lib/simple_enum/multiple/accessors/join_table_accessor.rb', line 7

def foreign_key
  @foreign_key
end

#remote_keyObject

Returns the value of attribute remote_key.



7
8
9
# File 'lib/simple_enum/multiple/accessors/join_table_accessor.rb', line 7

def remote_key
  @remote_key
end

#tableObject

Returns the value of attribute table.



7
8
9
# File 'lib/simple_enum/multiple/accessors/join_table_accessor.rb', line 7

def table
  @table
end

Instance Method Details

#changed?(object) ⇒ Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/simple_enum/multiple/accessors/join_table_accessor.rb', line 88

def changed?(object)
  object.send(:"#{source}_changed?")
end

#init(klass) ⇒ Object



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
# File 'lib/simple_enum/multiple/accessors/join_table_accessor.rb', line 9

def init(klass)
  klass_table_name = klass.table_name.to_s
  join_table_name = [klass_table_name, name.pluralize].sort.join("_").to_sym
  table = self.table = Arel::Table.new(join_table_name)

  source = self.source
  name = self.name

  foreign_key = self.foreign_key = klass_table_name.singularize.foreign_key
  remote_key = self.remote_key = name.singularize.foreign_key

  klass.class_eval do
    define_attribute_method source

    define_method source do
      instance_variable = instance_variable_get(:"@#{source}")
      return instance_variable if instance_variable
      sql = table.where(table[foreign_key].eq(self.id))
        .project(table[remote_key])
        .to_sql
      original_cds = ActiveRecord::Base.connection.send(:select, sql).rows.map(&:first).map(&:to_i)
      instance_variable_set(:"@#{source}", original_cds)
    end

    define_method :"#{source}=" do |current_cds|
      instance_variable = instance_variable_get(:"@#{source}")
      send("#{source}_will_change!") unless current_cds == instance_variable
      instance_variable_set(:"@#{source}", current_cds.select(&:present?).map(&:to_i))
    end

    define_method :"update_#{source}!" do
      return unless send(:"#{source}_changed?")
      original_cds = send(:"#{source}_was")
      current_cds = send(source)


      # if any enum been removed
      if (original_cds - current_cds).any?
        delete_sql = table.where(table[foreign_key].eq(self.id))
          .where(table[remote_key].in(original_cds - current_cds))
          .compile_delete
          .to_sql
        ActiveRecord::Base.connection.send(:delete, delete_sql)
      end

      # if any enum been added
      if (current_cds - original_cds).any?
        insert_sql = table.create_insert.tap do |insert_manager|
          insert_manager.into table
          insert_manager.columns << table[foreign_key]
          insert_manager.columns << table[remote_key]

          values = (current_cds - original_cds).map do |id|
            "(#{self.id}, #{id})"
          end.join(", ")
          insert_manager.values = Arel::Nodes::SqlLiteral.new("VALUES #{values}")
        end.to_sql
        ActiveRecord::Base.connection.send(:insert, insert_sql)
      end

      instance_variable_set(:"@#{source}_was", current_cds)
    end

    define_method :"clear_#{source}!" do
      delete_sql = table.where(table[foreign_key].eq(self.id))
        .compile_delete
        .to_sql
      ActiveRecord::Base.connection.send(:delete, delete_sql)
    end

    after_save :"update_#{source}!"
    after_destroy :"clear_#{source}!"
  end
end

#scope(collection, value) ⇒ Object



92
93
94
95
96
97
# File 'lib/simple_enum/multiple/accessors/join_table_accessor.rb', line 92

def scope(collection, value)
  join = Arel::Nodes::Group.new(table).to_sql
  on = collection.arel_table[collection.primary_key].eq(table[foreign_key]).to_sql
  collection.joins("INNER JOIN #{join} ON #{on}")
    .where(table[foreign_key].eq(value))
end

#was(object) ⇒ Object



84
85
86
# File 'lib/simple_enum/multiple/accessors/join_table_accessor.rb', line 84

def was(object)
  fetch_keys(object.send(:"#{source}_was").to_a)
end