Bazley
Bazley

Reputation: 2847

Rails updating column rows for has_one relationship

I have added iconfolio to my character model. Each character has_one :iconfolio.

character.rb

has_one :iconfolio, dependent: :destroy
accepts_nested_attributes_for :iconfolio
before_validation do
 self.create_iconfolio unless iconfolio
end

Here is the migration file:

class CreateIconfolios < ActiveRecord::Migration
  def change
    create_table :iconfolios do |t|
      t.integer :character_id

      t.string :icon_url

      t.timestamps null: false
    end
    add_index :iconfolios, :character_id
  end
end

The iconfolio class:

iconfolio.rb

class Iconfolio < ActiveRecord::Base

  belongs_to :character

  validates :character_id, presence: true

  before_create do
    self.icon_url = '/assets/icon1.png'
  end

end

Firstly, how do I ensure an iconfolio has been created for each character?

Secondly, how do I update all the rows in the character_id column? The character_id value is different for every iconfolio record. Updating the icon_url column can be done in the console:

Iconfolio.all.update_all(person_normal_icon_url: '/assets/icon1.png')

Upvotes: 0

Views: 279

Answers (1)

bkunzi01
bkunzi01

Reputation: 4561

The easiest way to do this is to create a default template iconfolio and update_all character records as you did with Iconfolio. If your database isn't already large you can iterate through Character.all and assign them an iconfolio. Be advised this will instantiate an object per row and be much more time consuming than update_all. The benefit of instantiating them is it will not bypass your validations. Write a block in your console that iterates through each record and finds or creates an iconfolio per character like:

  Character.all.find_each do |char|
     if char.iconfolio.blank?
          Iconfolio.create(character_id: char.id, whatever_other_params: put_here)
     end
  end

Then make an after_create in your Character model that creates and assigns an iconfolio for future new characters. Something like:

after_create :make_an_iconfolio

def make_an_iconfolio
   Iconfolio.create(character_id: self.id, other params here)
end

As a sidenote, the Rails way to add a relationship in your create_table migration is:

def change
    create_table :iconfolios do |t|
      t.belongs_to :character, index: true

This just makes it more clear to you and others that it's a relationship and saves an extra line of code from indexing.

Upvotes: 1

Related Questions