2016-04-27 1 views
2

Самый простой способ объяснить эту загадку является примере:Как цепочки один метод на другой изменение оригинального метода

Скажем, у меня есть два Mongoid модели, которые связаны через has_many отношений: блоге

class Post 
    include Mongoid::Document 
    field :body, type: String 

    has_many :comments 
end 

и это комментарии

class Comment 
    include Mongoid::Document 
    field :text, type: String 

    belongs_to :post 
end 

Теперь я создаю пост который имеет два комментария в IRB, и я пытаюсь загрузить их через отношения. У меня есть некоторые DB протоколирование включено, так что я могу видеть, когда запрос сделан:

post.comments #=> 
2016-04-27 13:51:52.144 [DEBUG MONGODB | localhost:27017 | test.find | STARTED | {"find"=>"comments", "filter"=>{"post_id"=>BSON::ObjectId('571f315e5a4e491a6be39e02')}}] 
2016-04-27 13:51:52.150 [DEBUG MONGODB | localhost:27017 | test.find | SUCCEEDED | 0.000492643s] 
=> [#<Comment _id: 571f315e5a4e491a6be39e03, text: 'great post' >, #<Comment _id: 571f315e5a4e491a6be39e12, text: 'this!' >] 

Поэтому комментарии загружаются из БДА и возвращаются как Mongoid::Relations::Targets::Enumerable класса, который выглядит как массив, и он содержит два комментария ,

Теперь, когда я открываю свежий IRB консоль, и посмотрите на критерии, используемые для загрузки эти комментарии с помощью атрибута экземпляра Mongoid::Relations::Targets::Enumerable класса post.commentscriteria, я получаю этот выход:

post.comments.criteria #=> 
=> #<Mongoid::Criteria 
selector: {"post_id"=>BSON::ObjectId('571f315e5a4e491a6be39e02')} 
options: {} 
class: Comment 
embedded: false> 

Как приходят в этом примере не выполняются запросы БД? Это не проблема кэширования, так как я открыл новую консоль IRB.

Как можно связать criteria с номером post.comments изменить то, что делает метод .comments? Я просмотрел реализацию Mongoid в классе Mongoid::Relations::Targets::Enumerable (source on Github), но не смог найти подсказки, как это работает.


Редактировать

Для выяснения вопроса:

Этот код не запрашивает базу данных:

post.comments.criteria 

Но этот код:

foo = post.comments 
post.comments.criteria 

Как так?

+1

Вы спрашиваете, как «post.comments.criteria» показывает селектор ObjectId? Если это так, ваш 'post' является переменной (класса Post), и он исходит оттуда. Поскольку переменная 'post' является классом Post, она понимает, что #comments является отношением (has_many). Короче говоря, я считаю, что вызов БД был сделан, когда ваша переменная 'post' была инициализирована. –

+1

Он не будет делать вызов БД до тех пор, пока вы не будете использовать метод запроса (см. Https://docs.mongodb.org/ecosystem/tutorial/mongoid-queries/). –

+0

@ wes.hysell Благодарим вас за комментарии. Если он вообще не должен делать вызов БД, то почему он делает это для меня? Я использую версию «Mongoid» 5.1.3 и rails '4.2.6' –

ответ

1

Преобразование комментариев к ответу:

При выполнении Mongoid::Relations::Targets::Enumerable#inspect метода инспектировать выполняется на всех записи:

инспекция просто проверить записи для хорошей печати массив стиля.

Это не может быть сделано без использования метода запроса.

Вопрос, который на самом деле имеет OP, больше связан с консолью IRB. Консоль IRB обрабатывает этот объект ответа таким образом, который вызывает #inspect и, в свою очередь, метод запроса. Для классов Mongoid (и ActiveRecord) метод #inspect выполняет запрос для получения ожидаемого результата.

К примеру, это вызовет запрос к базе данных, если побежал в IRB консоли:

>> foo = posts.comments 
>> post.comments.criteria 

Реакция foo вызовет метод запроса, когда IRB попытки консоли к выходу объекта в ответ , Запрос к БД может быть подавлено в IRB консоли в (по крайней мере) один из двух способов:

Метод 1: and nil

По существу, вы можете использовать суффиксы одну команду с and nil или ;0 или что-то аналогично тому, как первая команда не обрабатывается выходным сигналом IRB. Это связано с тем, что консоль IRB смотрит только на последний объект (например, на возврат рубинового метода).

>> foo = posts.comments and nil 
>> post.comments.criteria 

, приведенный выше, не будет запрашивать базу данных, так как выходной сигнал обрабатывается IRB на первой линии nil вместо переменной foo.

Способ 2: conf.echo = false

Источник: https://stackoverflow.com/a/13284331/1483788

Этот метод предотвращает IRB консоли от обработки ответа объекты автоматически.

>> conf.echo = false  
>> foo = posts.comments 
>> post.comments.criteria 

Это не будет запрашивать базу данных с консоли. Тем не менее, вы также не получите ответ от последней строки. Вам нужно будет использовать puts или pp (довольно печатать) для вывода объекта. Для сравнения, если вы используете команду foo.inspect при использовании этого метода, вы заметите, что запрос к db выполняется для получения желаемого результата.

1

post.comments - это то, что вы бы назвали «объектом запроса». Другими словами, он содержит всю необходимую информацию для извлечения необходимых данных из базы данных, но не самих данных. Когда вы вызываете post.comments.criteria, он просто отображает соответствующие параметры, которые хранит объект запроса, чтобы выполнить запрос. Идентификатор объекта доступен здесь, потому что post уже существует в памяти.

Этот же принцип применим к post.comments.to_sql, если вы использовали базу данных sql.

+0

Спасибо за объяснение Энтони. Я понимаю, как работает объект запроса. Я отредактировал вопрос, чтобы уточнить, что я просил –

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