瘦controller,富model

----先看這麼一段rhtml代碼:渲染模板中加入了這麼多的邏輯,看起來不倫不類,這麼做行是行,但是缺點很多,新手一般有這個毛病。那麼這樣做,首先是可讀性很差,因爲在渲染代碼中最好都是貼近HTML代碼,而這堆代碼裏把C的內容也加進來了。

<% people = Person.find(
:conditions => ["added_at > ? and deleted = ?", Time.now.utc, false],
:order => "last_name, first_name") %>
<% people.reject { |p| p.address.nil? }.each do |person| %>
<div id="person-<%= person.new_record? ? "new" : person.id %>">
<span class="name">
<%= person.last_name %>, <%= person.first_name %>
</span>
<span class="age">
<%= (Date.today - person.birthdate) / 365 %>
</span>
</div>
<% end %>

再看看controller和model裏的東西:

# app/controllers/people_controller.rb
class PeopleController < ActionController::Base
end

# app/models/person.rb
class Person < ActiveRecord::Base
has_one :address
end

空蕩蕩的controller,而在model裏僅僅有一句關係聲明。這麼組合成的MVC顯得很彆扭,似乎就是一層渲染模板。幾乎把C與M都忽略了。

無論如何這在MVC框架裏是糟糕透頂的現象,MVC經過這麼多年的實踐考驗,它的優點在於“可讀性強”“可維護性好”“模塊化”“關注點的分離”等等,我想你用MVC框架也就是想實現這些優點哇?那麼首先需要改進的是儘可能的將邏輯內容搬到controller中,controller 的作用就是介於view和model之間,起到一個類似中介的作用。下面來看下這樣改動之後的代碼:

<!-- app/views/people/index.rhtml -->
<% @people.each do |person| %>
<div id="person-<%= person.new_record? ? "new" : person.id %>">
<span class="name">
<%= person.last_name %>, <%= person.first_name %>
</span>
<span class="age">
<%= (Date.today - person.birthdate) / 365 %>
</span>
</div>
<% end %>



# app/controllers/people_controller.rb
class PeopleController < ActionController::Base
def index
@people = Person.find(
:conditions => ["added_at > ? and deleted = ?", Time.now.utc, false],
:order => "last_name, first_name")
@people = @people.reject { |p| p.address.nil? }
end
end

這樣看起來就好多了,模板中的代碼更像是HTML的結構,而且你粗略的看一下controller裏的代碼就能知道在這個action渲染的模板中會顯示什麼數據。

還可以更進一步做的事情就是將現在模板代碼中關於一部分數據的處理挪到Model中來:

# app/models/person.rb
class Person < ActiveRecord::Base
# ...

def name
"#{last_name}, #{first_name}"
end

def age
(Date.today - person.birthdate) / 365
end

def pseudo_id
new_record? ? "new" : id
end
end


<!-- app/views/people/index.rhtml -->
<% @people.each do |person| %>
<div id="person-<%= person.pseudo_id %>">
<span class="name"><%= person.name %></span>
<span class="age"><%= person.age %></span>
</div>
<% end %>

這樣通過在model中添加幾個虛擬屬性,在view裏調用,顯得很合理,而且模板代碼更簡潔明瞭了。

下一步就是將controller裏的代碼理一理。因爲controller只能算是個中介,不應該參與很多的邏輯處理。

# app/models/person.rb
class Person < ActiveRecord::Base
def self.find_recent
people = find(
:conditions => ["added_at > ? and deleted = ?", Time.now.utc, false],
:order => "last_name, first_name")
people.reject { |p| p.address.nil? }
end

# ...
end


# app/controllers/people_controller.rb
class PeopleController < ActionController::Base
def index
@people = Person.find_recent
end
end

現在看index這個action,掃一眼就知道它要幹嗎。而且如果find_recent方法在以後需要改變時,可以直接在model裏進行修改。

--總結一下,儘量使得controller的actions中的代碼和view中的代碼更少,在action中要是能只寫一行達到效果最好。在view中要儘量使代碼貼近html結構。

還有一個不太明顯的好處就是,瘦action可以使得 respond_to 結構更突出,可以看出輸出的類型是什麼。

class PeopleController < ActionController::Base
def index
@people = Person.find_recent

respond_to do |format|
format.html
format.xml { render :xml => @people.to_xml(:root => "people") }
format.rss { render :action => "index.rxml" }
end
end
end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章