Rails:通过比较两个模型进行过滤

时间:2018-11-13 21:34:59

标签: ruby-on-rails ruby match filtering

我对两个模型之间的匹配感到困惑。我已经研究了stackoverflow和google,直到2天了,但是没有办法... 关于匹配和过滤还有更多的问题和答案,但这只是一种搜索,列出的方式。可能是我不确定我不确定。 例如: 我的应用程序中包含内容和用户。 我分享了内容,但不想让所有用户都喜欢它。 用户应该看到谁;

  • 大于18岁且小于70岁。
  • 必须住在英格兰和 伦敦市。 (可以更改)
  • 它们必须具有驱动器许可证
  • 性别:男士bla bla等。

我的第一个想法是为用户创建个人资料并从他们那里获取信息。 另外,为Content模型创建配置文件过滤器,并填写像belov这样的表格。

但是问题已经到了最后一步; “我如何比较它们,只有用户才能看到并喜欢谁具有与Content过滤器属性相同的真实属性。

模型;

UserContent

Profile所属user

Contentfilter所属Content

比; 如果current_user配置文件属性与“内容”过滤器相同,则显示内容。

您有什么建议吗? 谢谢。

1 个答案:

答案 0 :(得分:0)

我将假设您的意思是任何匹配的内容,但我将为所有或任何匹配的配置文件过滤器提供解决方案。

这是关于如何实现所需目标的一种快速解决方案。

给出以下模型:

# 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"]

该解决方案通过与ProfileUser共享多态Content模型来工作。然后,通过将用户的Content属性传递给查询来查询属于User类型的配置文件,它将ProfileContent实例进行匹配。

请注意,#all_matching_content方法要求所有配置文件属性都匹配,基本上这意味着查询中的所有条件都经过“与”运算。 #any_matching_content方法改为使用“ OR”条件。

我已将一个快速项目上传到GitHub,该示例已被编码:

https://github.com/JurgenJocubeit/so-53289847