布尔字段,指示记录与给定字段值具有所属关联

时间:2015-04-04 14:24:41

标签: ruby-on-rails ruby sqlite activerecord rails-activerecord

我的模特:

class CountryVisit < ActiveRecord::Base
  belongs_to :country
  belongs_to :user

  validates :country, uniqueness: { scope: user, message: 'already visited' }
end

class User < ActiveRecord::Base
  has_many :country_visits

  ...
end

class Country < ActiveRecord::Base
  has_many :country_visits

  ...
end

我希望每个国家/地区都有一个虚拟属性,表明它对给定用户

country_visit

Country.for(user)

这是我不完整的解决方案(如果我尝试对结果执行ActiveRecord::StatementInvalid: SQLite3::SQLException,则会引发.count):

def self.for(user_id)
  Country
    .select("countries.*, country_visits.id AS visited")
    .joins(
      "LEFT OUTER JOIN country_visits ON 
      country_visits.country_id = countries.code 
      AND country_visits.user_id = #{user_id}"
    )
end

预期行为:

user = User.create

#with country visit
c1 = Country.create
cv1 = CountryVisit.create(country: c1, user: user)

#without country visit
c2 = Country.create

结果应该是:

countries = Country.for(user_id).order('created_at asc')
countries.first.visited # => true
countries.last.visited # => false

1 个答案:

答案 0 :(得分:0)

实际上这里的问题非常简单。如果你看一下完整的错误:

ActiveRecord::StatementInvalid: SQLite3::SQLException: unrecognized token:
"#": SELECT countries.*, country_visits.id AS visited FROM "countries" LEFT 
OUTER JOIN country_visits ON country_visits.country_id = countries.id AND 
country_visits.user_id = #<User:0x007fcb357a5ed8>  ORDER BY created_at asc

请注意上面显示的#<User:0x007fcb357a5ed8>?这是因为在for方法中您传递的是完整的用户对象,而不是用户ID。而且由于您正在编写原始SQL,因此活动记录不足以将AR对象强制转换为ID。

解决此问题的最简单方法是将您的国家/地区方法更改为:

def self.for(user) # <-- user
  Country
    .select("countries.*, country_visits.id AS visited")
    .joins(
      "LEFT OUTER JOIN country_visits ON 
      country_visits.country_id = countries.code 
      AND country_visits.user_id = #{user.id}"   # <-- user.id
    )
end