Я предполагаю, что вы имеете в виду любой соответствующий контент, но я предоставляю решение для ВСЕХ или ЛЮБЫХ фильтров соответствия профиля.
Вот одно быстрое решение о том, как вы можете достичь того, чего хотите.
Учитывая следующие модели:
# app/models/user.rb
class User < ApplicationRecord
has_one :profile, as: :profilable
def all_matching_content
profile: Profile.where(
"? >= age", profile.age).
where(
gender: profile.gender,
city: profile.city,
license: profile.license).
where(profilable_type: "Content"))
end
def any_matching_content
Content.where(
profile: Profile.where("? >= age", profile.age).
or(Profile.where(gender: profile.gender)).
or(Profile.where(city: profile.city)).
or(Profile.where(license: profile.license)).
where(profilable_type: "Content"))
end
end
end
# app/models/profile.rb
class Profile < ApplicationRecord
belongs_to :profilable, polymorphic: true, optional: true
end
# app/models/content.rb
class Content < ApplicationRecord
has_one :profile, as: :profilable
end
И следующие миграции:
# db/migrate/20181114004031_create_users.rb
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name, index: true
t.timestamps
end
end
end
# db/migrate/20181114004134_create_profiles.rb
class CreateProfiles < ActiveRecord::Migration[5.2]
def change
create_table :profiles do |t|
t.references :profilable, polymorphic: true, null: true
t.boolean :license, index: true
t.string :city, index: true
t.string :gender, index: true
t.integer :age, index: true
t.timestamps
t.index [:license, :city, :gender, :age], name: "profile_composite_index"
end
end
end
# db/migrate/20181114004307_create_contents.rb
class CreateContents < ActiveRecord::Migration[5.2]
def change
create_table :contents do |t|
t.string :title, index: true
t.timestamps
end
end
end
И следующие семена:
# db/seeds.rb
User.create!(
name: "John",
profile: Profile.create!(
license: true,
city: "London",
gender: "Male",
age: 19
)
)
User.create!(
name: "Jane",
profile: Profile.create!(
license: false,
city: "London",
gender: "Female",
age: 17
)
)
User.create!(
name: "Rose",
profile: Profile.create!(
license: true,
city: "Edinburgh",
gender: "Female",
age: 21
)
)
User.create!(
name: "Hans",
profile: Profile.create!(
license: true,
city: "Berlin",
gender: "Male",
age: 24
)
)
Content.create!(
title: "London introduces new tax",
profile: Profile.create!(
city: "London"
)
)
Content.create!(
title: "New license requirements in Berlin",
profile: Profile.create!(
city: "Berlin",
license: true
)
)
Content.create!(
title: "Women should get new immunization",
profile: Profile.create!(
gender: "Female"
)
)
Content.create!(
title: "Adults only expo opens Wednesday",
profile: Profile.create!(
age: 18
)
)
Вы будетеуметь выполнять следующие действия:
> john = User.find_by(name: "John")
> john.all_matching_content
=> #<ActiveRecord::Relation []>
> john.any_matching_content.map(&:title)
=> ["London introduces new tax", "New license requirements in Berlin", "Adults only expo opens Wednesday"]
> jane = User.find_by(name: "Jane")
> jane.any_matching_content.map(&:title)
=> ["London introduces new tax", "Women should get new immunization"]
> rose = User.find_by(name: "Rose")
> rose.any_matching_content.map(&:title)
=> ["New license requirements in Berlin", "Women should get new immunization", "Adults only expo opens Wednesday"]
> hans = User.find_by(name: "Hans")
> hans.any_matching_content.map(&:title)
=> ["New license requirements in Berlin", "Adults only expo opens Wednesday"]
Решение работает путем совместного использования полиморфной модели Profile
с User
и Content
.Затем он сопоставляет Content
с экземпляром User
, передавая атрибуты пользователя Profile
в запрос на сопоставление профилей, принадлежащих к типам Content
.
Обратите внимание, что метод #all_matching_content
требует, чтобы всеАтрибуты профиля совпадают, в основном это означает, что все условия в запросе - "И".Вместо этого метод #any_matching_content
использует условия «ИЛИ».
Я загрузил быстрый проект в GitHub с уже закодированным примером:
https://github.com/JurgenJocubeit/so-53289847