active record gem

* Rails consoleで何か変更ある時、`reload!`でreloadする

```rb
> reload!
```

* レガシーシステム(legacy system)がconvention over configurationに反する場合、カスタマイズできる点

```rb
class User < ActiveRecord::Base
  self.table_name = "USER"
  self.primary_key = "user_id"
  self.table_name_prefix = "hello_"
  self.table_name_suffix = "_tokyo"
end
```

* column読む三つの方法

```rb
user.email
user[:email]
user.read_attribute(:email)
```

* serializeとstoreので項目の値をyml、jsonでDBに保存する
  デメリットがあるので、慎重に検討！
  http://qiita.com/jnchito/items/68e91e9bf46f960a79e4

* model objectの新規？DBから読み取った状態？削除状態？の判断
　DBの実際状態とは関係ない！？

```rb
user.new_record?
user.persisted? # DBから読み取ったrecord＋まだdestroy処理を行ってない
user.destroyed? # DBから読み取った後、destroy処理を行った
```

* model object作成

```rb
user = User.new do |user|
  user.name = "tom"
end
user.save
user.save!

User.create(name: "tom", email: "hoge@gmail.com")
User.create!(name: "tom", email: "hoge@gmail.com")
```

* get with primary key

```rb
User.find(1) # throw RecordNotFound Exception if no record
User.find([1, 2]) # throw RecordNotFound Exception if some record can't be found.
```

* convert model to Hash

```rb
user.attributes
```

* modify attributes without saving

```rb
user.name = "xx"
user[:name] = "xx"
user.write_attribute(:name, "xx")
user.attributes = {name:"tt", email: "hoge@mail.com"} # update specified columns only
user.assign_attributes({name:"tt", email:"hoge"}) # update specified columns only
user.attributes[:name] = "xx" # user.attributes is not changed!! never use this.
```

* modify attributes and save to DB

```rb
user.save
user.update(name:"kk",email:"xx@gmail.com")
user.update_attributes(name:"kk22",email:"xx22@gmail.com") # update_attributes is alias of update
user.update!(name:"kk",email:"xx@gmail.com")
user.update_attributes!(name:"kk22",email:"xx22@gmail.com")
user.update_attribute(:email, "xx") # update one attribute without validation, callbacks are executed, updated_at is changed
user.update_column(:email, "xx") # update one attribute without validation, callbacks are not executed, updated_at is not changed.
```
* update and get model (will exec validation)

```rb
user = User.update(2, {email:"hello"})
# return model whether success or failure
#   or ActiveRecord::RecordNotFound
user.valid?
```
is similar to

```rb
user = User.find(2)
user.update({email:"hello"}) # return true or false
```

* update all record (no validation here !!)

```rb
User.update_all({email:"xx",name:"xx"})
```

* other update method: increment, increment!, decrement, decrement!,toggle, toggle!, touch
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html
 
* read raw attribute value

```rb
user.attributes_before_type_cast
user.read_attribute_before_type_cast(:created_at)
user.created_at_before_type_cast # "2017-03-27 05:16:50.821663"
user.created_at # Mon, 27 Mar 2017 05:16:50 UTC +00:00
```

* clone vs dup

* query cache
Query is cached in a hash {SQL => result set]}
If the SQL is **exactly the same** as SQL in cache, the cached result will be used.

```rb
ActiveRecord::Base.connection.disable_query_cache!

ActiveRecord::Base.connection.enable_query_cache!

ActiveRecord::Base.connection.clear_query_cache

ActiveRecord::Base.connection.uncached do # uncached in this block
   ....
end

ActiveRecord::Base.connection.cache do # cached in this block
   User.where("id =  1").first
   User.where("id =  1").first # get the Result in cache
   User.where("id =    1").first # not exactly the same!
end

ActiveRecord::Base.connection.instance_variable_get(:@query_cache) # get current cache
```

* **readonly** attributes
you can set readonly attributes, but the changes will never be saved to DB

```rb
class User < ApplicationRecord
  attr_readonly :email
end
```

* Delete
destroy will load instance first and then calls destroy on it.

```rb
user.destroy
user.destroy!
User.delete(1)
User.delete([1])
User.destroy(1)
User.destroy([1,2])
```

* Optimistic Locking
add **lock_version* column to table first

```rb
  add_column :users, :lock_version, :integer, default: 0
```

When lock_version is changed, the update will rails ActiveRecord::StableObjectError.

* basic where conditions

```rb
Product.where(sku: 11) # where sku = 11
Product.where(sku: [1,2,3]) # where sku in (1,2,3)
Product.where(sku: []) # where 1=1
Product.where(sku: [1]) # where sku=1
Product.where('descript like ? and color = ?', "%xx%", "red")
Product.where("sku in (?)", [1, 2, 3])
```

* where with bind variables

```rb
User.where("name = :xx and location = :xx", xx: "superman")
```

* where (not equal and not in)

```rb
Product.where.not(name: "x") # name != "x"
Product.where.not(sku: [1,2]) # sku not in (1,2)
```

* where (boolean)

```rb
User.where('active = ?', true)
```

* where(is null)

```rb
User.where(email: nil)
User.where.not(email: nil)
```

* order clause

```rb
User.order("name desc, email asc")
User.order(name: :desc, email: :asc) # use different cache key to above one
``` 

* limit and offset

```rb
User.limit(10).offset(10)
```

* select column

```rb
User.select("*", "salary * 2 as bonus").fisrt.bonus
```

* from

```rb
def self.find_xxx
  select("users.*").
    from("users, locations").
    where("xxxxxx")
end
```

* check the existence of records

```rb
User.exists(1)
User.exists(name: "xx")
Use.where(admin: true).exist?
```

* **includes,eager_load,preload** and **joins**
http://qiita.com/k0kubun/items/80c5a5494f53bb88dc58

* ActiveRecord::NullRelation
  cause a query to return zero records
https://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/none

```rb
@posts = current_user.visible_posts.where(name: params[:name])
# => the visible_posts method is expected to return a chainable Relation

def visible_posts
  case role
  when 'Country Manager'
    Post.where(country: country)
  when 'Reviewer'
    Post.published
  when 'Bad User'
    Post.none # => returning [] instead breaks the previous code
  end
end
```

* order, reorder, reverse_order

* uniq/distinct

```rb
User.select(:sex).uniq # select distinct sex from users
```