Skip to content

Instantly share code, notes, and snippets.

@takuyan
Last active March 17, 2018 08:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takuyan/370adf5327604d8fb0891c58dc310ffc to your computer and use it in GitHub Desktop.
Save takuyan/370adf5327604d8fb0891c58dc310ffc to your computer and use it in GitHub Desktop.

Rails v1.0 読書会

ORMまわりを中心に読む

  • findしたものをARにどうやって詰めるのか

読書メモ

lib/active_record/base.rb:430 find_by_sql

# Works like find(:all), but requires a complete SQL string. Examples:
#   Post.find_by_sql "SELECT p.*, c.author FROM posts p, comments c WHERE p.id = c.post_id"
#   Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date]
def find_by_sql(sql)
  connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
end

lib/active_record/connection_adapters/abstract/database_statements.rb:6

def select_all(sql, name = nil)
end

lib/active_record/connection_adapters/mysql_adapter.rb:170

def select_all(sql, name = nil) #:nodoc:
  select(sql, name)
end

lib/active_record/connection_adapters/mysql_adapter.rb:320

def select(sql, name = nil)
  @connection.query_with_result = true
  result = execute(sql, name)
  rows = []
  if @null_values_in_each_hash
    result.each_hash { |row| rows << row }
  else
    all_fields = result.fetch_fields.inject({}) { |fields, f| fields[f.name] = nil; fields }
    result.each_hash { |row| rows << all_fields.dup.update(row) }
  end
  result.free
  rows
end

lib/active_record/base.rb:887

# Finder methods must instantiate through this method to work with the single-table inheritance model
# that makes it possible to create objects of different types from the same table.
def instantiate(record)
  object = 
    if subclass_name = record[inheritance_column]
      if subclass_name.empty?
        allocate
      else
        require_association_class(subclass_name)
        begin
          compute_type(subclass_name).allocate
        rescue NameError
          raise SubclassNotFound,
            "The single-table inheritance mechanism failed to locate the subclass: '#{record[inheritance_column]}'. " +
            "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
            "Please rename this column if you didn't intend it to be used for storing the inheritance class " +
            "or overwrite #{self.to_s}.inheritance_column to use another column for that information."
        end
      end
    else
      allocate
    end

  object.instance_variable_set("@attributes", record)
  object
end

なぜ allocate ?? newしたらだめなの?

def initialize(attributes = nil)
  @attributes = attributes_from_column_definition
  @new_record = true
  ensure_proper_type
  self.attributes = attributes unless attributes.nil?
  yield self if block_given?
end

DB定義からattributesを組み立てる

# Initializes the attributes array with keys matching the columns from the linked table and
# the values matching the corresponding default value of that column, so
# that a new instance, or one populated from a passed-in Hash, still has all the attributes
# that instances loaded from the database would.
def attributes_from_column_definition
  self.class.columns.inject({}) do |attributes, column|
    attributes[column.name] = column.default unless column.name == self.class.primary_key
    attributes
  end
end

つぎにこれ。

@new_record = true

たしかに検索結果は new_record ではないしな

# Allows you to set all the attributes at once by passing in a hash with keys
# matching the attribute names (which again matches the column names). Sensitive attributes can be protected
# from this form of mass-assignment by using the +attr_protected+ macro. Or you can alternatively
# specify which attributes *can* be accessed in with the +attr_accessible+ macro. Then all the
# attributes not included in that won't be allowed to be mass-assigned.
def attributes=(attributes)
  return if attributes.nil?
  attributes.stringify_keys!

  multi_parameter_attributes = []
  remove_attributes_protected_from_mass_assignment(attributes).each do |k, v|
    k.include?("(") ? multi_parameter_attributes << [ k, v ] : send(k + "=", v)
  end
  assign_multiparameter_attributes(multi_parameter_attributes)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment