Смена Rails - PullRequest
       22

Смена Rails

0 голосов
/ 11 января 2012

Я пытаюсь найти способ изменить отношение принадлежащие, has_many от нормального и ожидаемого (см. Ниже) поведения на обоих ...

'SELECT `transactions`.* FROM `transactions` WHERE `transactions`.`account_id` = 2'

на

'SELECT `transactions`.* FROM `transactions` WHERE `transactions`.`account_id` = 2' OR `transactions`.`transfer_id` = 3'

Текущая настройка ...

class Account < ActiveRecord::Base
  has_many :transactions
end

class Transaction < ActiveRecord::Base
  belongs_to :account
end

class CreateTransactions < ActiveRecord::Migration
  def change
    create_table :transactions do |t|
      t.string        :name,
      t.references    :account,
      t.timestamps
    end
  end
end

Попытка решения ...

class Account < ActiveRecord::Base
  has_many :transactions, :class_name => "Transaction", :finder_sql => ->(record) do
    record = self if(record.nil?)
    "SELECT * FROM transactions WHERE transactions.account_id = #{record.id} OR transactions.transfer_id = #{record.id}"
  end
end

class Transaction < ActiveRecord::Base
  belongs_to :transfer, :class_name => "Account", :foreign_key => 'transfer_id'
end

class CreateTransactions < ActiveRecord::Migration
  def change
    create_table :transactions do |t|
      t.string        :name,
      t.references    :account,
      t.integer       :transfer_id,
      t.timestamps
    end
  end
end

Вопрос в том, как изменить значение по умолчанию, ГДЕ, чтобы включить ИЛИ.Добавление области или дополнения к has_many без использования foreign_key, похоже, приводит к ...

'SELECT transactions. * FROM transactions WHERE transactions. account_id = 2' (И transactions. transfer_id = 3 ')

Фактически все мои попытки использования рельсов обычными способами, кажется, приводят к вышесказанному.

Важность разработки того, какизмените отношение по умолчанию, чтобы все операторы выбора, ищущие account_id, также смотрели на Transfer_id.

Ваша помощь будет принята с благодарностью.

1 Ответ

2 голосов
/ 11 января 2012

Извините, но я не верю, что has_many поддерживает то, что вы ищете. По соглашению ожидается, что ассоциация будет ссылаться на все данные ключи. В вашем случае вы пытаетесь сослаться на один из нескольких ключей.

Самое простое решение - создать 2 отдельные ассоциации, а затем объединить их при необходимости:

class Account < ActiveRecord::Base
  has_many :transactions # this will use the 'account_id' field by convention
  has_many :transfer_transactions, :class_name => "Transaction", :foreign_key => :transfer_id
  def all_transactions
    (transactions + transfer_transactions).uniq
  end
end

Недостатком является то, что вы делаете 2 вызова базы данных, а метод #all_transactions не будет доступен как вложенная ассоциация.

Другая возможность состоит в том, чтобы пересмотреть вашу схему и создать 2 записи транзакции на физическую транзакцию с пометкой направления дебет / кредит. В любом случае это больше соответствует учету двойной записи:

class Account < ActiveRecord::Base
  has_many :transactions

  def credit_transactions
    transactions.credit
  end

  def debit_transactions
    transactions.debit
  end
end

class Transaction < ActiveRecord::Base
  belongs_to :account
  # add some validation to make sure you set the debit/credit flag

  scope :credit, where(:credit => true)
  scope :debit, where(:credit => false)

  # some virtual accessors for 'debit'
  def debit=(direction)
    credit = !direction
  end
  def debit?
    !credit?
  end
end

class CreateTransactions < ActiveRecord::Migration
  def change
    create_table :transactions do |t|
      t.string        :name
      t.references    :account
      t.boolean :credit, :nil => false
      t.timestamps
    end
  end
end

Еще одна опция, на которую вы, возможно, захотите взглянуть, это драгоценный камень 'Squeel'. Это в основном ruby ​​DSL для SQL, и он позволяет выполнять всевозможные сложные запросы. Однако я не уверен, будет ли это работать в объявлении has_many.

...