01 - Begin from linter : rails_best_practices
好的開始,是成功的一半。
不管是前端、後端,當一個團隊每個成員撰寫程式的風格不同,對於維護、開發都相對會困難些。如果有個統一的規定,會一定程度提高專案開發效率。這類型的 tools 在每個程式都有相對應的 linter 可以使用。
這次開頭第一篇就從名字很淺顯易懂的 rails_best_practices
開始吧!一看就知道這個 gem 在做什麼(雖然說 官方網站 已經有點久沒更新 & Github Commit 沒什麼新的東西,但至少還是一個不錯使用的工具,也在上個專案使用了約一年多左右)
gem install
1 2
| gem "rails_best_practices"
|
Usage
1 2 3 4 5
| bundle exec rails_best_practices
bundle exec rails_best_practices -f html
|
以 User has_many post 的例子來看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| create_table "posts", force: :cascade do |t| t.string "title" t.text "content" t.boolean "is_available" t.integer "user_id", null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.index ["user_id"], name: "index_posts_on_user_id" end
create_table "users", force: :cascade do |t| t.string "name" t.string "email" t.string "tel" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end
class User < ApplicationRecord has_many :posts end
class Post < ApplicationRecord belongs_to :user end
|
在 post index 頁面中,假如想顯示 Post 所有欄位 & 來自於哪個 User Name,可能會這樣子寫:
1 2 3 4 5 6 7 8 9 10
| <% @posts.each do |post| %> <tr> <td><%= post.title %></td> <td><%= post.content %></td> <td><%= post.is_available %></td> # User Name <td><%= post.user.name %></td> </tr> <% end %>
|
執行 bundle exec rails_best_practices
會發現出現 law of demeter
的錯誤訊息,原因其實就是出在 post.user.name
的部分
1 2 3 4 5
| /blog/app/views/posts/index.html.erb:22 - law of demeter
Please go to https://rails-bestpractices.com to see more useful Rails Best Practices.
Found 1 warnings.
|
可以寫個 user_name
方法來呼叫關聯 user 的 name,不過如果要顯示 user 更多的其他欄位(e.g. email
),等於要一直寫更多的方法,這時候其實可以用 delegate 來做,相對於行數也比較短。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
class User < ApplicationRecord has_many :posts end
class Post < ApplicationRecord belongs_to :user
def user_name user.name end
def user_email user.email end
delegate :name, :email, to: :user, prefix: true end
<% @posts.each do |post| %> <tr> <td><%= post.title %></td> <td><%= post.content %></td> <td><%= post.is_available %></td> # User Name & Email <td><%= post.user_name %></td> <td><%= post.user_email %></td> </tr> <% end %>
|
透過 Delegate 來把 attributes 給關聯的 model 來使用讓邏輯更容易理解,更改後再跑一次就 No warning found,沒問題啦!
1 2 3 4 5
| Source Code: |=============================================================================================================================|
Please go to https://rails-bestpractices.com to see more useful Rails Best Practices.
No warning found. Cool!
|
RubyGems
參考來源