Можно ли делегировать метод ассоциации has_many
в рельсах, И все еще сохранять предварительно загруженные данные в этой ассоциации, все время, следуя закону деметатора? В настоящее время мне кажется, что вы вынуждены выбирать тот или иной. То есть: сохраняйте свои предварительно загруженные данные НЕ делегируя или теряя предварительно загруженные данные и делегируя.
Пример: у меня есть следующие две модели:
class User < ApplicationRecord
has_many :blogs
delegate :all_have_title?, to: :blogs, prefix: false, allow_nil: false
def all_blogs_have_title?
blogs.all? {|blog| blog.title.present?}
end
end
class Blog < ApplicationRecord
belongs_to :user
def self.all_have_title?
all.all? {|blog| blog.title.present?}
end
end
Обратите внимание: что User#all_blogs_have_title?
выполняет то же самое, что и метод делегирования all_have_title?
.
Следующее, как я понимаю, нарушает закон demeter. Однако: он поддерживает ваши предварительно загруженные данные:
user = User.includes(:blogs).first
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
Blog Load (0.1ms) SELECT "blogs".* FROM "blogs" WHERE "blogs"."user_id" = 1
=> #<User id: 1, name: "all yes", created_at: "2017-12-05 20:28:00", updated_at: "2017-12-05 20:28:00">
user.all_blogs_have_title?
=> true
Обратите внимание: когда я вызывал user.all_blogs_have_title?
, он НЕ делал дополнительный запрос. Однако обратите внимание, что метод all_blogs_have_title?
задает вопрос о атрибутах Blog
, что нарушает закон demeter.
Другой способ, который применяет закон demeter, но вы теряете предварительно загруженные данные:
user = User.includes(:blogs).first
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
Blog Load (0.1ms) SELECT "blogs".* FROM "blogs" WHERE "blogs"."user_id" = 1
=> #<User id: 1, name: "all yes", created_at: "2017-12-05 20:28:00", updated_at: "2017-12-05 20:28:00">
user.all_have_title?
Blog Load (0.2ms) SELECT "blogs".* FROM "blogs" WHERE "blogs"."user_id" = ? [["user_id", 1]]
=> true
Мы надеемся, что недостатки обеих реализаций очевидны. В идеале: я хотел бы сделать это вторым способом с реализацией делегата, но для поддержания этих предварительно загруженных данных. Возможно ли это?