2013-04-15 2 views
0

В модели Rails 3.2, надеялся создать «to_csv» метод класса для создания CSV выход из сферы ActiveRecord, как это:ActiveRecord :: Отношение хитов метод массива вместо моего метода класса

class Post 
    # ... 
    def self.to_csv(options = {}) 
    CSV.generate(options) do |csv| 
     scoped.each {|post| csv << record.attributes.values_at('title', 'text')} 
    end 
    end 
end 

Я ожидал, что я мог бы использовать его как это:

User.first.posts.to_csv 

Однако этот метод, как представляется, переопределить метод массива #to_csv. Даже если я делаю это:

User.first.posts.scoped.to_csv 

... и результат от User.first.posts.scoped явно ActiveRecord :: Отношения, я до сих пор попал метод Array. Если я переименую метод на что-то вроде «to_csvx», он работает так, как ожидалось.

Я надеюсь, что кто-то может объяснить, как/почему объект ActiveRecord :: Relation предпочтительно удаляет метод Array #to_csv вместо метода to_csv. Хотя это (метод класса, ожидающий вызова по объему AR) кажется правдоподобным, мне интересно, есть ли неотъемлемая проблема всей идеи?

+0

На первый взгляд это похоже на http://stackoverflow.com/questions/224128/how-do-you-make-a-method-apply-to-a-collection-of-activerecord-objects, но Фактическая точка этого вопроса заключается в том, как я могу получить записи, которые мне нужно скрывать, связывая это в конце цепочки отношений вместо того, чтобы передавать их в качестве аргумента. –

+1

Я просто угадываю здесь: ваш метод 'Array # to_csv', кажется, исходит из патча gem/monkey (AFAIK это не из рельсов). Возможно, этот драгоценный камень также обезьяна исправляет 'Relation', чтобы делегировать' to_csv' 'to_a' (см. [ActiveRecord :: Delegation] (https://github.com/rails/rails/blob/master/activerecord/lib/active_record /relation/delegation.rb)). Это объясняет вашу проблему и почему используется другое имя метода. –

+0

Я должен был заметить версию Ruby (1.9.3) Метод Array to_csv показан здесь: http://apidock.com/ruby/Array/to_csv –

ответ

4

OK, супер-хромой для ответа на свой вопрос, но, основываясь на комментарий от @m_x и Railscast 239 http://railscasts.com/episodes/239-activerecord-relation-walkthrough я глубже в исходный код Rails ... Я могу видеть, что соотношение respond_to почести, и method_missing предпочитает метод массива к любому другому методу, явно не определенному для Relation.

# from rails/active_record/relation/delegation.rb 

def respond_to?(method, include_private = false) 
    super || Array.method_defined?(method) || 
    @klass.respond_to?(method, include_private) || 
    arel.respond_to?(method, include_private) 
end 

protected 

def method_missing(method, *args, &block) 
    if Array.method_defined?(method) 
    ::ActiveRecord::Delegation.delegate method, :to => :to_a 
    to_a.send(method, *args, &block) 
    elsif @klass.respond_to?(method) 
    ::ActiveRecord::Delegation.delegate_to_scoped_klass(method) 
    scoping { @klass.send(method, *args, &block) } 
    elsif arel.respond_to?(method) 
    ::ActiveRecord::Delegation.delegate method, :to => :arel 
    arel.send(method, *args, &block) 
    else 
    super 
    end 
end 

Итак, если имя методы «обзорный» класс ActiveRecord так же, как метод экземпляра массива, то связь будет преобразована в массив и методы массива будут вызываться вместо вашего метода класса.

Простое решение: просто выберите другое имя метода.

+2

Это не хромой, чтобы ответить на ваш собственный вопрос, ведь вы даже должны его принять. Способствует SO и помогает людям ... приятно копаться в источнике. Мне кажется странным, что методы массива предпочтительнее, чем методы отношения, возможно, вы должны предложить патч для рельсов на github –

Смежные вопросы