Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
19
Help us understand the problem. What is going on with this article?
@mechamogera

railsでdb:migrateした後railsプロセス再起動が必要な理由

More than 5 years have passed since last update.

理由

  • モデルがカラムの情報をキャッシュして持っているから
    • 間違ってたら突っ込み希望です

参照サイト

db:migrate後のモデル操作例

  • 以下のようなコードを用意する
# db/migrate/20140306063809_create_products.rb
class CreateProducts < ActiveRecord::Migration
  def change
    create_table :products do |t| 
      t.string :name

      t.timestamps
    end 
  end 
end

# app/models/product.rb
class Product < ActiveRecord::Base    
  attr_accessible :name
end
  • db:migrateする
  • Productデータを用意しておく
  • Productにhogeカラムを追加する
# db/migrate/20140306065532_add_hoge_to_product.rb
class AddHogeToProduct < ActiveRecord::Migration
  def change
    Product.first
    add_column :products, :hoge, :string
    Product.first.update_attributes! hoge: 'muga'
  end 
end

# app/models/product.rb
class Product < ActiveRecord::Base
  attr_accessible :name, :hoge
end
  • db:migrateする
  • Product.firstを確認する => hogeがnil
    • 最初のProduct.firstをなくした場合にはhogeはmuga => 初回参照時にDB参照かな
    • 最初のProduct.firstをなくしてinitializerでProductモデルを利用した場合はhogeがnil
    • Product.reset_column_informationをしてupdate_attributes!するとhogeはmuga
    • config.cache_classes = trueにするとdevelopmentでrails sした環境でも確認可能

ちょっとコードを追ってみる

  • デバッグ中心でしか見てないけど、、、

  • update_attributes!の中を追ってみるとsave!でcolumnで持っていないカラムは無視してそう

# activerecord-3.2.17/lib/active_record/persistence.rb

# save!で呼び出されている
def update(attribute_names = @attributes.keys)
  attributes_with_values = arel_attributes_values(false, false, attribute_names) # ここで保持していないカラムは無視
  return 0 if attributes_with_values.empty?
  klass = self.class
  stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values) # updateのsqlクエリ生成
  klass.connection.update stmt
end 
# activerecord-3.2.3/lib/active_record/attribute_methods.rb
...
    def column_for_attribute(name)
      self.class.columns_hash[name.to_s] # カラム持ってないとnil
    end
...
    def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
      attrs      = {}
      klass      = self.class
      arel_table = klass.arel_table

      attribute_names.each do |name|
        if (column = column_for_attribute(name)) && (include_primary_key || !column.primary) # column_for_attributeでnilになると何もしない

          if include_readonly_attributes || !self.class.readonly_attributes.include?(name)

            value = if klass.serialized_attributes.include?(name)
                      @attributes[name].serialized_value
                    else
                      # FIXME: we need @attributes to be used consistently.
                      # If the values stored in @attributes were already type
                      # casted, this code could be simplified
                      read_attribute(name)
                    end

            attrs[arel_table[name]] = value
          end
        end
      end

      attrs
    end
  • カラム初アクセスの時にDB接続にいってあとは保持しているっぽい
# activerecord-3.2.17/lib/active_record/model_schema.rb 

# Returns an array of column objects for the table associated with this class.
def columns
  @columns ||= connection.schema_cache.columns[table_name].map do |col|
    col = col.dup
    col.primary = (col.name == primary_key)
    col
  end
end 
# activerecord-3.2.17/lib/active_record/connection_adapters/schema_cache.rb

module ActiveRecord
  module ConnectionAdapters  
    class SchemaCache
      attr_reader :primary_keys, :tables
      attr_reader :connection

      def initialize(conn)
        @connection = conn
        @tables     = {}

        @columns = Hash.new do |h, table_name|
          h[table_name] = connection.columns(table_name, "#{table_name} Columns")
        end
        ...
      end
...
      # Get the columns for a table
      def columns(table = nil)
        if table
          @columns[table]
        else
          @columns
        end
      end
...
    end
  end
end 
19
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
mechamogera
https://github.com/mechamogera/MyTips/wiki で技術メモを登録してましたが使いやすそうなので引っ越してみました。 保有資格:CSM、EXIN Agile Scrum Foundation、AWS認定ソリューションアーキテクトプロフェッショナル、Ruby技術者認定試験Silver/Gold、SJC-P/SJC-D、ソフトウェア開発技術者、基本情報技術者
jrits
信頼と魅力のある先進のITをもとに、お客様のワークスタイル・イノベーションの実現を目指します。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
19
Help us understand the problem. What is going on with this article?