0

So I have a service object that submits up votes and voted users into a database:

Here's the posts model:

class Post < ActiveRecord::Base
  attr_accessible :comment_count, :downvote, :id, :text, :title, :upvote, :url, :user_id, :users_voted_up_by, :users_voted_down_by

  serialize :users_voted_up_by, Array
  serialize :users_voted_down_by, Array

  belongs_to :user
end

Here's the User model:

class User < ActiveRecord::Base
  attr_accessible :email, :password, :password_confirmation, :username, :good_karma, :bad_karma, :posts_voted_up_on, :posts_voted_down_on

  serialize :posts_voted_up_on, Array
  serialize :posts_voted_down_on, Array

  has_many :posts

  attr_accessor :password
  before_save :encrypt_password

  validates_confirmation_of :password
  validates_presence_of :password, :on => :create
  validates_presence_of :email
  validates_uniqueness_of :email
  validates_presence_of :username
  validates_uniqueness_of :username

  def self.authenticate(email, password)
    user = find_by_email(email)
    if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
      user
    else
      nil
    end
  end

  def encrypt_password
    if password.present?
      self.password_salt = BCrypt::Engine.generate_salt
      self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
    end
  end
end

Now here's my Voter class that controls up votes and down votes.

class Voter
  def initialize(post, user)
    @post = post
    @user = user
  end

  def upvote
    return false unless @post.users_voted_up_by
    @post.upvote += 1
    @post.users_voted_up_by << @user.username
    @user.good_karma += 1
    @post.save && @user.save
  end

  def downvote
    return false unless @post.users_voted_down_by
    @post.upvote += 1
    @post.users_voted_down_by << @user.username
    @user.bad_karma += 1
    @post.save && @user.save
  end
end

It adds and retrevies the first one fine:

User1

But when I perform another "upvote" with a different user, instead of adding it to the array it just adds it to the string like this:

User1User2

Am I not using the line correctly?

@post.users_voted_up_by << @user.username

3
  • It would help if we could see the model relationships in this instance Commented Jan 10, 2013 at 10:00
  • Are you sure this isn't just the to_s method. What does @post.users_voted_up_by.join(', ') produce? Commented Jan 10, 2013 at 10:07
  • Undefined method "join". It's not just .to_s, serialize stores the integrity of the array in the database, or it should, I don't think I'm using it correctly. I need an example, but can't find one. Commented Jan 10, 2013 at 10:10

1 Answer 1

1

You're trying to model a many-to-many relationship via serialized arrays. In my opinion this is a misuse of Rails serialization feature.

The more appropriate way to design your problem is to create a Vote model which belongs to User and has one Post. It is better both in design perspective and db-performance perspective.

Once you do that you won't add users to a post votes array, you will just create a new Vote instance with the voter (user) id and the post id.

Sign up to request clarification or add additional context in comments.

6 Comments

Wont' that table quickly become massive? Have have a third table with thousands of rows when you can have 3 more columns that contain an integer.
It will become massive but thanks to today's modern SQL engines and good indices on the right columns queries on that table will be very fast.
Do I need a controller for this Vote model as well?
No controller needed. It would just be a more solid design.
I'd definitely create a VotesController to handle all vote operations.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.