开发者

Has many through associations with conditions

开发者 https://www.devze.com 2023-04-10 04:23 出处:网络
I am trying to add a condition to a has many through association without luck. This is the association in my video model:

I am trying to add a condition to a has many through association without luck. This is the association in my video model:

has_many :voted_users, :through => 开发者_C百科:video_votes, :source => :user

I want to only get the voted_users whose video_votes have a value equal to 1 for that video. How would I do this?


I would suggest creating a model method within the video model class Something like:

def users_with_one_vote
  self.voted_users, :conditions => ['value = ?', 1]
end

Then in the controller use video.users_with_one_vote

Then testing is easier too.

Any chance you can change that column name from 'value'. Might give some issues (reserved?).


I'd do this in 2 stages:

First, I'd define the has_many :through relationship between the models without any conditions.

Second, I'd add a 'scope' that defines a where condition.

Specifically, I'd do something like:

class User < ActiveRecord::Base
  has_many :video_votes
  has_many :votes, :through=>:video_votes
  def self.voted_users
    self.video_votes.voted
  end
end

class VideoVote
  def self.voted
    where("value = ?", 1)
  end
end

class Video
  has_many :video_votes
  has_many :users, :through=>:video_votes
end

Then you could get the users that have voted using:

VideoVote.voted.collect(&:user).uniq

which I believe would return an array of all users who had voted. This isn't the exact code you'd use -- they're just snippets -- but the idea is the same.


Would

has_many :voted_users, :through => :video_votes, :source => :user, :conditions => ['users.votes = ?', 1]

Do the trick?


I found that defining this method in my model works:

def upvoted_users
  self.voted_users.where("value = 1")
end

and then calling @video.upvoted_users does the trick.


The best way to do this without messing with the relations is by crafting a more complex query. Relations is not the best thing to use for this particular problem. Please understand that relations is more a "way of data definition" then a way of "bussiness rules definition".

Bussiness logic or bussiness rules must be defined on a more specifically layer.

My suggestion for your problem is to create a method to search for users who voted on your video only once. something like:

class Video < ActiveRecord::Base

  def voted_once()
    User.joins(:video_votes).where("video_votes.value == 1 AND video_votes.video_id == ?", this.id)
  end

Rails is magical for many things, but complex queries still have to be done in a "SQL" way of thinking. Don't let the illusional object oriented metaphor blind you


As long as we are throwing around ideas, how about using association extensions.

class VideoVote
  scope :upvotes, where(:value => 1)
end

class Video
  has_many :voted_users, :through => :video_votes, :source => :user do
    def upvoted
      scoped & VideoVote.upvotes
    end
  end
end

Then you feel good about making a call with absolutely no arguments AND you technically didn't add another method to your Video model (it's on the association, right?)

@video.voted_users.upvoted
0

精彩评论

暂无评论...
验证码 换一张
取 消