Строчные условия в «магических» методах для Model - PullRequest
0 голосов
/ 19 февраля 2012

Модель Country имеет атрибут code, который автоматически преобразуется в нижний регистр обратным вызовом before_save. Можно ли навязать это поведение «магическим» методам, не переписывая большие куски ActiveRecord :: Base?

class Country < ActiveRecord::Base
  attr_accessible :code
  validates :code, :presence => true
  validates_uniqueness_of :code, :case_sensitive => false

  before_save do |country|
    country.code.downcase! unless country.code.nil?
  end
end

RSpec

describe Country do
  describe 'data normalization'
    before :each do
      @country = FactoryGirl.create(:country, :code => 'DE')
    end

    # passes
    it 'should normalize the code to lowercase on insert' do
      @country.code.should eq 'de'
    end

    # fails
    it 'should be agnostic to uppercase finds' do
      country = Country.find_by_code('DE')
      country.should_not be_nil
    end 

    # fails
    it 'should be agnostic to uppercase finds_or_creates' do
      country = Country.find_or_create_by_code('DE')
      country.id.should_not be_nil # ActiveRecord Bug?
    end
end

1 Ответ

0 голосов
/ 20 февраля 2012

Это то, что я придумал, хотя я действительно ненавижу этот подход (как упоминалось в вопросе). Простая альтернатива - установить столбец, таблицу или всю базу данных так, чтобы игнорировать регистр (но это db dependendt).

class Country < ActiveRecord::Base
  attr_accessible :code
  validates :code, :presence => true
  validates_uniqueness_of :code, :case_sensitive => false

  before_save do |country|
    country.code.downcase! unless country.code.nil?
  end

  class ActiveRecord::Base
    def self.method_missing_with_code_finders(method_id, *arguments, &block)
      if match = (ActiveRecord::DynamicFinderMatch.match(method_id) || ActiveRecord::DynamicScopeMatch.match(method_id))
        attribute_names = match.attribute_names
        if code_index = attribute_names.find_index('code')
          arguments[code_index].downcase!
        end
      end
      method_missing_without_code_finders(method_id, *arguments, &block)
    end

    class << self
      alias_method_chain(:method_missing, :code_finders)
    end
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...