Ruby on Rails 網站程式設計基礎班

第十二課:開發自己的 gem
公告
1. 請繳回門禁卡
2. 完成留言板
- 至少要有使用者登入登出功能
- 將寫好的留言板上架至 Heroku
- 死線是 11/27/2016 晚上 11:59:59
3. 寫下你對這堂課的建議 (至少兩項)
Rails Module
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
has_many :votes, as: :voteable
validates :content, presence: true, length: {minimum: 5}
def up_votes
self.votes.where(vote: true).length
end
def down_votes
self.votes.where(vote: false).length
end
def total_votes
up_votes - down_votes
end
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
has_many :categories_posts
has_many :categories, through: :categories_posts
has_many :votes, as: :voteable
def up_votes
self.votes.where(vote: true).length
end
def down_votes
self.votes.where(vote: false).length
end
def total_votes
up_votes - down_votes
end
end
兩個需要投票的 model 有太多一樣的程式碼, 遵守 DRY 的原則,我們應該要把一樣的程式碼打包起來,集中到一個地方管理
Rails Module
# 我們到 /lib 底下,增加一個新檔案 voteable.rb
module Voteable
def up_votes
self.votes.where(vote: true).length
end
def down_votes
self.votes.where(vote: false).length
end
def total_votes
up_votes - down_votes
end
end
Rails Module
class Post < ActiveRecord::Base
include Voteable
belongs_to :user
has_many :comments
has_many :categories_posts
has_many :categories, through: :categories_posts
has_many :votes, as: :voteable
end
class Comment < ActiveRecord::Base
include Voteable
belongs_to :user
belongs_to :post
has_many :votes, as: :voteable
validates :content, presence: true, length: {minimum: 5}
end
有了 Voteable 模組後,我們只需 include 它就可使用定義在 Voteable 內的方法,原本和在 model 裡面和 voteable 相關的方法就可以移除掉
Rails Module
require File.expand_path('../boot', __FILE__)
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Postboard2
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.autoload_paths += %W(#{config.root}/lib)
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
# Do not swallow errors in after_commit/after_rollback callbacks.
config.active_record.raise_in_transactional_callbacks = true
end
end
最後需要通知 rails 載入 /lib 路徑下的檔案
把 module 打包成 gem
先到 https://rubygems.org/ 註冊帳號
把 module 打包成 gem
# 跳出 rails 專案,在 terminal 輸入...
bundle gem 你的_gem_名稱
# 到.gemspec檔裡,把以下程式碼註解掉...
spec.homepage = "TODO: Put your gem's website or public repo URL here."
if spec.respond_to?(:metadata)
spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
else
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
end
把 module 打包成 gem
到 /lib 底下,打開 .rb 檔,在裡面加入我們的 voteable 程式碼
module 你的module名稱
def up_votes
self.votes.where(vote: true).length
end
def down_votes
self.votes.where(vote: false).length
end
def total_votes
up_votes - down_votes
end
end
把 module 打包成 gem
接下來執行:
gem build 你的_gem_名稱.gemspec
成功的話會在資料夾裡產生一個 .gem 檔,接下來就:
gem push .gem檔的名稱
成功!妳已經把 Gem 發佈在 rubygems.org 上面了! 接下來你就可以透過把它寫進 Gemfile 然後執行 bundle 把它裝起來
module vs gem
1. 放在 /lib 裡的 module,是整合跨 model 的一些功能,但是是專門為該 Rails 專案客製化的功能
2. 如果今天同樣的 module 也適合在其他不同的 Rails 專案重複使用,那就應該把該 module 打包成一個 gem,讓它能被快速安裝在不同的 rails 專案裡
deck
By Eugene Chang
deck
- 1,025