реализация ruby ​​on rails с именованной областью

Из книги Agile Web Development with Rails

class Order < ActiveRecord::Base
   named_scope :last_n_days, lambda { |days| {:conditions =>
      ['updated < ?' , days] } }

   named_scope :checks, :conditions => {:pay_type => :check}
end

Заявление

orders = Orders.checks.last_n_days(7)

приведет только к одному запросу к базе данных.

Как рельсы это реализуют? Я новичок в Ruby, и мне интересно, есть ли специальная конструкция, которая позволяет этому происходить.

Чтобы иметь возможность связывать такие методы, функции, сгенерированные named_scope, должны возвращать себя или объект, область действия которого может быть расширена. Но как Ruby узнает, что это последний вызов функции и что сейчас нужно запросить базу данных?

Я спрашиваю об этом, потому что приведенный выше оператор фактически запрашивает базу данных, а не просто возвращает оператор SQL, полученный в результате цепочки.


person Heinrich Lee Yu    schedule 09.04.2010    source источник


Ответы (3)


В магии named_scope используются два трюка (или шаблона, если хотите).

Шаблон прокси — вызов метода именованной области для класса или ассоциации всегда возвращает экземпляр класса ActiveRecord::NamedScope::Scope, а не набор отфильтрованных объектов AR. . Этот шаблон, хотя и очень полезный, иногда делает вещи размытыми, поскольку прокси-объекты амбивалентны по своей природе.

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

И последнее замечание: есть одна вещь, которую нужно иметь в виду, играя с именованными областями (или с чем-либо, что использует какое-либо делегирование) в IRB. Каждый раз, когда вы нажимаете Enter, то, что вы написали заранее, оценивается, и для возвращаемого значения вызывается метод inspect. В случае связанных именованных областей, несмотря на то, что все выражение оценивается в экземпляре области, когда IRB вызывает для него метод inspect, области оцениваются и запускается запрос к базе данных. Это вызвано тем фактом, что метод inspect посредством делегирования распространяется на все объекты области вплоть до базовой коллекции.

person Milan Novota    schedule 09.04.2010

Вы можете попробовать это

class Order < ActiveRecord::Base

  class << self
    def last_n_days(n)
      scoped(:conditions => ['updated < ?', days])
    end
    def checks
      scoped(:conditions => {:pay_type => :check})
    end
  end

end

использование такое же

@orders = Order.last_n_days(5)
@orders = Order.checks
@orders = Order.checks.last_n_days(5)

Это по-прежнему делает всю ленивую загрузку, которую вы любите. То есть он не будет делать запрос, пока вы не попытаетесь получить доступ к записям. Бонус: совместимость с Rails 3!

Именованные области действия мертвы

person maček    schedule 10.04.2010

Очень круто. Я думал сделать что-то подобное в Javascript, но Javascript ведет себя довольно странно.

Заявление:

var x = SomeObject;

не вызывает функцию SomeObject toString(). Но утверждение:

var x;
x = SomeObject;

правильно вызывает функцию toString(), как и ожидалось.

Это не позволяет Javascript делать классные вещи с цепочкой. знак равно

person Heinrich Lee Yu    schedule 09.04.2010