ActiveRecord

[color=blue]ActiveRecord 4新特性 [url]http://www.oschina.net/translate/get-your-app-ready-for-rails-4?print[/url][/color]

ActiveRecord 范围需要一个 Callable 对象。

在 Rails 4 中,所有 ActiveRecord 范围必须使用一个 callable 对象来定义:
#Rails 3.2
scope :recent, where(created_at: Time.now - 2.weeks)
#Rails 4
scope :recent, -> { where("created_at > ?", Time.now - 2.weeks).order("created_at desc") }
scope :active, -> { where(status: 'active') }

Activerecord-deprecated-finders 是 Rails 4.0 中默认提供废弃功能的依赖包,但它也将在 4.1 版本中被删除。因此你需要密切关注所有的警告信息,并开始修复这些警告。

Rails 指南 提供一个很有用的解释,关于在大多数情况下如何修改动态查找器:

所有动态的方法除了 findby… 和 findby…! 外都已废弃,你可以使用如下的替代方法:

find_all_by_...改为 where(...).
find_last_by_...改为 where(...).last.
scoped_by_...改为 where(...).
find_or_initialize_by_...改为 where(...).first_or_initialize.
find_or_create_by_...改为 find_or_create_by(...) 或者 where(...).first_or_create.
find_or_create_by_...!改为 find_or_create_by!(...) 或者 where(...).first_or_create!.


[color=blue]#1 Caching with Instance Variables[/color]
@current_user ||= User.find(session[:user_id])


[color=blue]#2 Dynamic find_by Methods[/color]

@tasks = Task.find(:all, :conditions => ['complete = ?', false])
=>
@tasks = Task.find_all_by_complete(false)

@task = Task.find(:first, :conditions => ['complete =?', false], :order => 'created_at DESC')
=>
@task = Task.find_by_complete(false, :order => 'created_at DESC')


[color=blue]#3 Find Through Association[/color]

from
@tasks = Task.find(:all, :conditions => ['project_id = ? AND complete = ?', @project.id, false])

to (推荐使用,用association 进行关联)
@project = Project.find(params[:id])
@tasks = Task.find(:all, :conditions => ['project_id = ? AND complete = ?', @project.id, false])


[color=blue]#4 Move Find into Model[/color]
Move a find into the model to clean up the controllers and remove duplication. 
将 find 转移到model中,清洁controllers
from

class TaskController < ApplicationController
def index
@tasks = Task.find_all_by_complete(:false, :order => "created_at DESC")
end
end

to
class Task < ActiveRecord::Base
belongs_to :project
def self.find_incomplete
find_all_by_complete(:false, :order => "created_at DESC")
end
end


[color=blue]#5 Using with_scope[/color]

class Task < ActiveRecord::Base
belongs_to :project

def self.find_incomplete(options = {})
with_scope :find => options do
find_all_by_complete(false, :order => 'created_at DESC')
end
end
end
@tasks = @project.tasks.find_incomplete :limit => 20


[color=blue]#6 Shortcut Blocks with Symbol to_proc[/color]
projects.collect { |p| p.name } => ["Write another ASCIIcast", "Go out walking"]
projects.collect {&:name} => ["Write another ASCIIcast", "Go out walking"]
projects.collect(&:name).collect(&:upcase) => ["WRITE ANOTHER ASCIICAST", "GO OUT WALKING"]

projects.each {|project| project.save!}
==
projects.each(&:save!)


[color=blue]#16: Virtual Attributes (revised)[/color]
简介:对原生的attributes(collums),进行逻辑封装

schema.rb
create_table "products", :force => true do |t|
t.string "name"
t.integer "price_in_cents"
t.datetime "released_at"
... ...
end

1、转换 {price_in_cents => price_in_dollars}


<%= f.label :price_in_dollars %>
<%= f.text_field :price_in_dollars %>

attr_accessible :name, :price_in_dollars
def price_in_dollars
price_in_cents.to_d/100 if price_in_cents
end
def price_in_dollars=(dollars)
self.price_in_cents = dollars.to_d*100 if dollars.present?
end

2、对 released_at 进行逻辑封装 {release_at => relese_at_text}

attr_writer :released_at_text
validate :check_released_at_text
before_save :save_released_at_text
def released_at_text
@released_at_text || released_at.try(:strftime, "%Y-%m-%d %H:%M:%S")
end

def save_released_at_text
self.released_at = Time.zone.parse(@released_at_text) if @released_at_text.present?
end

def check_released_at_text
if @released_at_text.present? && Time.zone.parse(@released_at_text).nil?
errors.add :released_at_text, "cannot be parsed"
end
rescue ArgumentError
errors.add :released_at_text, "is out of range"
end


3、支持创建新的 category
<%= f.label :category_id %><br />
<%= f.collection_select :category_id, Category.order(:name), :id, :name %>
or create one:<%= f.text_field :new_category %>

attr_accessible :new_category
attr_accessor :new_category
before_save :create_category #在保存 product 前,先前所依赖的 category创建出来

def create_category
self.category = Category.create!(name: new_category) if new_category.present?
end


[color=blue]#17、habtm-checkboxs[/color]
典型的多对多的关系 ,且使用关联表Categorization
class Product < ActiveRecord::Base
has_many :categorizations
has_many :categories, through: :categorizations
end

class Categorization < ActiveRecord::Base
belongs_to :category
belongs_to :product
end

class Category < ActiveRecord::Base
has_many :categorizations
has_many :products, through: :categorizations
end

rails consle分析
p=produc.first => select "products".* from "products" limit 1
p.category_ids => select categories.id from categories inner join categorizations on categories.id=categorization.category_id where categorizations.product_id=1
p.category_ids=[1,2] =>
1、select * from categories where id IN (1,2)
2、select * from categories inner join categorizations on categoris.category_id=categorization.category_id where categorizations.product_id=1
3、insert into categorizations ... values category_id=1,product_id=1
4、insert into categorizations ... values category_id=2,product_id=1
p.categories =>[#<Category id=1 .....>,#<Category id=2 ....>]


_form.html.erb

<%= hidden_field_tag "product[category_ids][]", nil %>
<% Category.all.each do |category| %>
<%= check_box_tag "product[category_ids][]", category.id, @product.category_ids.include?(category.id), id: dom_id(category) %>
<%= label_tag dom_id(category), category.name %>
<% end %>
</div>



[color=blue]#15 Fun with Find Conditions[/color]
# When searching for null values the correct syntax would be priority IS NULL, not priority = NULL
Task.find(:all, :conditions => ["completed = ? AND priority = ?", false, 2])
SELECT * FROM "tasks" WHERE (completed = 'f' AND priority = 2)


Task.find(:all, :conditions => ["complete=? and priority IS ?", false, nil])
SELECT * FROM "tasks" WHERE (completed = 'f' AND priority is NULL)

Task.find(:all, :conditions => ["complete=? and priority IN (?)", false, [1,3]])
Task.find(:all, :conditions => ["complete=? and priority IN (?)", false, 1..3])

Task.find(:all, :conditions => { :complete => false, :priority => 1 })
Task.find(:all, :conditions => { :complete => false, :priority => nil })

Task.find(:all, :conditions => { :completed => false, priority => [1,3] }
SELECT * FROM "tasks" WHERE (completed = 'f' AND priority IN (1,3)

Task.find(:all, :conditions => {:completed => false, priority => 2..4})
SELECT * FROM "tasks" WHERE ("tasks"."priority" BETWEEN 2 AND 4 AND "tasks"."completed" = 'f')

Task.find_by_priority(1..5)
SELECT * FROM "tasks" WHERE ("tasks"."priority" BETWEEN 1 AND 5) LIMIT 1


[color=blue]
#14 Performing Calculations on Models[/color]
Task.first.priority      => 3
SELECT * FROM "tasks" LIMIT 1

Task.sum(:priority) => 12
SELECT sum("tasks".priority) AS sum_priority FROM "tasks"

Task.sum(:priority, :conditions => {:completed => false }) => 2
SELECT sum("tasks".priority) AS sum_priority FROM "tasks" WHERE (completed="f")

Task.minimum(:priority) => 2
SELECT min("tasks".priority) AS min_priority FROM "tasks"

Task.maximum(:priority) => 5
SELECT max("tasks".priority) AS max_priority FROM "tasks"

Task.average(:priority).to_f => 3.0
SELECT avg("tasks".priority) AS avg_priority FROM "tasks"

#Using the methods through associations.
project = Project.first => #<Project id: 1, title: "A Project">
project.tasks.sum(:priority, :conditions => {:completed => true}) => 10

SELECT sum("tasks".priority) AS sum_priority FROM "tasks"
WHERE ("tasks"."completed" = 't') AND ("tasks".project_id = 1)



[color=blue]
#22 Eager Loading[/color]
<% @tasks.each do |task| %>
<li><%= link_to task.name, task %> in <%= task.project.name %></li>
<% end %>


terminal

Project Load (0.2ms) SELECT * FROM "projects" WHERE ("projects"."id" = 60)
CACHE (0.0ms) SELECT * FROM "projects" WHERE ("projects"."id" = 60)
CACHE (0.0ms) SELECT * FROM "projects" WHERE ("projects"."id" = 60)
CACHE (0.0ms) SELECT * FROM "projects" WHERE ("projects"."id" = 60)
CACHE (0.0ms) SELECT * FROM "projects" WHERE ("projects"."id" = 60)

解决方案
1、eager loading reduce the calls to the database even further.
We enable it by making a change in the TasksController.


class TasksController < ApplicationController
def index
@tasks = Task.find(:all, :include => :project)
end
end


2、Including More Than One Association

class Task < ActiveRecord::Base
belongs_to :project
has_many :comments
end

class TasksController < ApplicationController
def index
@tasks = Task.find(:all, :include => [:project, :comments])
end
end

3、more complex associations.

class Comment < ActiveRecord::Base
belongs_to :task
belongs_to :user
end

@tasks = Task.find(:all, :include => [:project, {:comments => :user }])


[color=blue]#23 Counter Cache Column[/color]
class Task < ActiveRecord::Base
belongs_to :project, :counter_cache => true
has_many :comments
end

migrations/006_add_tasks_count.rb
def self.up
add_column :projects, :tasks_count, :integer, :default => 0
Project.reset_column_information
Project.find(:all).each do |p|
Project.update_counters p.id, :tasks_count => p.tasks.length
end
end
def self.down
remove_column :projects, :tasks_count
end

console
p = Project.first
=> #<Project id: 61, name: "Project 1", created_at: "2009-01-26 20:34:36", updated_at: "2009-01-26 22:05:22", tasks_count: 20>
>> p.tasks.create(:name => "New task")
=> #<Task id: 1201, name: "New task", project_id: 61, created_at: "2009-01-26 22:24:13", updated_at: "2009-01-26 22:24:13">

The project’s counter cache has been updated.


[color=blue]#28 in_groups_of[/color]

ruby teminal

a = (1..12).to_a => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
a.in_groups_of(4) => [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
a.in_groups_of(3) => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
a.in_groups_of(5) => [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, nil, nil, nil]]
a.in_groups_of(5, false) => [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12]]
a.in_groups_of(5, 0) => [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 0, 0, 0]]

rails

<table>
<% @tasks.in_groups_of(4) do |tasks| %>
<tr>
<% tasks.each do |task| %>
<td><%= task.name %></td>
<% end %>
</tr>
<% end %>
</table>




[color=blue]#29 group_by Month[/color]
a = (1..20).to_a            => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
a.group_by { |num| num/5 } => {0=>[1, 2, 3, 4], 1=>[5, 6, 7, 8, 9], 2=>[10, 11, 12, 13, 14], 3=>[15, 16, 17, 18, 19], 4=>[20]}

class TasksController < ApplicationController
def index
@tasks = Task.all
@task_months = @tasks.group_by { |t| t.due_at.beginning_of_month }
end
end

<% @task_months.keys.sort.each do |month| %>
<h2><%= month.strftime("%B %Y") %></h2>
<% for task in @task_months[month] %>
<p><b><%= task.name %></b> due at <%= task.due_at.to_date.to_s(:long) %></p>
<% end %>
<% end %>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值