1

I am trying to insert a row into the join table, that I created in this migration (with timestamp):

class CreateUserNewsItemJoinTable < ActiveRecord::Migration
  def change
    create_join_table :users, :news_items do |t|
      t.timestamps
    end

    add_index :news_items_users, [:user_id, :news_item_id], unique: true
  end
end

This is how I insert NewsItem into User:

@user.news_items << @news_item

The first time, it was inserted successfully. But if I insert the same record again, it shows UniqueViolation.

How can I make the identical insert, to update timestamp, instead of throwing UniqueViolation error?

Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
VHanded
  • 2,079
  • 4
  • 30
  • 55
  • You are trying to do an *upsert* . It's not as simple as you'd think. For some non-Rails-specific info, see http://stackoverflow.com/q/17267417/398670 – Craig Ringer Sep 03 '14 at 09:39

1 Answers1

2

You don't want to insert again, you want to update the join table.

According to the rails guides If you need to work with the join table at all, it should have it's own model:

The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don't need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you'll need to remember to create the joining table in the database).

Therefore, create the model and use a has_many_through.

You'll then be able to do:

item = UserNewsItem.find_by(news_id: x, user: y)
item.update_attribute(:updated_at, Time.now)
Yule
  • 9,668
  • 3
  • 51
  • 72
  • Thanks, I end up creating a model, like your suggestion. But I used this: read = Read.find_or_initialize_by(:user_id => @user.id, :news_item_id => news_item.id).update_attributes(:updated_at => Time.now) – VHanded Sep 04 '14 at 02:17