第六日已建立了虛擬轉址信箱的機制,而今天是再結合第三日及第五日的內容,讓 RoR 提供可多人使用去修改自己轉址信箱的界面。
建置策略
利用 RoR 建立一個資料表,做為 /etc/mail/virtusertable 的內容依據,只要每次資料庫有做增減的動作,就把 table 的內容整個重寫到該檔案。每個人所設的虛擬信箱名稱,彼此不能重覆,自己只新增、修改、刪除自己所建立的項目,不能去改別人的項目。也不能去看別人設了哪些名稱及轉信到什麼地方。
讓 virtusertable 可讓 RoR 寫入
先確認一下自己是以什麼身份及群組來跑 RoR ,看 gid 是什麼,使以下檔案設成可被 RoR 的 group 寫入的屬性,此例的 group 是 users
id
# 假設所獲得 gid 或 groups 是 users
su -
cd /etc/mail
chgrp users virtusertable virtusertable.db
chmod g+w virtusertable virtusertable.db
RoR 的規畫
以下要進行這樣的動作:先 scaffold 產生 vtable 的 CRUD 等五個動作,而表格里面要有的欄份分別是「user 的 id」、「虛擬郵件帳號名稱」、「轉寄到真正信箱的所在」,而這三個欄位內容不能是空的。然後編輯 Vtable 這個 Model ,檢查 vname 不要有其他的符號存入,也檢查 forward 為符合 email 地址的 pattern。
由於在IT邦幫忙的文章中,加太多段【code】,像超過9個或10個以後,到後面的幾段的 code 的區塊,反而無法正常出現,所以把大部份的程式碼及一些說明就都寫在一起。
cd test1
./script/generate scaffold vtable user_id:integer vname:string forward:string
#執行後所出現的最後一行的訊息類似:
# create db/migrate/20080920223335_create_vtables.rb 編輯此檔案內容,
# --- db/migrate/20080920223335_create_vtables.rb 開始 ---
class CreateVtables < ActiveRecord::Migration
def self.up
create_table :vtables do |t|
t.integer :user_id, :null => false
t.string :vname, :null => false
t.string :forward, :null => false
t.timestamps
end
end
def self.down
drop_table :vtables
end
end
# --- db/migrate/20080920223335_create_vtables.rb 結束 ---
#記得執行 此動作,將上述所定義的欄位屬性,寫到資料庫中
rake db:migrate
# 然後編輯 app/models/user.rb 加上 has_many :vtables 類似這樣的位置:
# ---app/models/user.rb 開始 ---
require 'digest/sha1'
class User < ActiveRecord::Base
has_many :vtables
# Virtual attribute for the unencrypted password
....
# ---app/models/user.rb 結束 ---
# 編輯 --- app/models/vtable.rb 開始 ---
class Vtable < ActiveRecord::Base
belongs_to :user
validates_uniqueness_of :vname, :case_sensitive => false
validates_format_of :forward, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
validates_format_of :vname, :with => /\A[a-z0-9\._-]*\Z/i
validates_length_of :vname, :in => 3..20, :allow_nil => false
end
# --- app/models/vtable.rb 結束 ---
修改雛型來符合建置策略
vi app/controllers/vtables_controller.rb
class VtablesController < ApplicationController
include AuthenticatedSystem
before_filter :login_required
def index
# 修改始
# @vtables = Vtable.find(:all)
@vtables = Vtable.find_all_by_user_id(current_user.id)
# 修改結束
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @vtables }
end
end
def show
@vtable = Vtable.find(params[:id])
# 新增始
if @vtable.user_id != current_user.id
flash[:notice] = '不可偷看不是自己帳號的內容!'
render :text => '不可偷看不是自己帳號的內容!'
return
end
# 新增結束
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @vtable }
end
end
def new
@vtable = Vtable.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @vtable }
end
end
# GET /vtables/1/edit
def edit
@vtable = Vtable.find(params[:id])
# 新增始
if @vtable.user_id != current_user.id
flash[:notice] = '不可偷改不是自己帳號的內容!'
render :text => '不可偷改不是自己帳號的內容!'
return
end
# 新增結束
end
def create
@vtable = Vtable.new(params[:vtable])
# 新增始
if @vtable.user_id != current_user.id
flash[:notice] = '不可偷新增不是自己帳號的內容!'
render :text => '不可偷新增不是自己帳號的內容!'
return
end
# 新增結束
respond_to do |format|
if @vtable.save
flash[:notice] = 'Vtable was successfully created.'
format.html { redirect_to(@vtable) }
format.xml { render :xml => @vtable, :status => :created, :location => @vtable }
# 寫到 /etc/mail/virtusertable 及生效的動作
output
else
format.html { render :action => "new" }
format.xml { render :xml => @vtable.errors, :status => :unprocessable_entity }
end
end
end
def update
@vtable = Vtable.find(params[:id])
# 新增始
if @vtable.user_id != current_user.id
flash[:notice] = '不可偷更新不是自己帳號的內容!'
render :text => '不可偷更新不是自己帳號的內容!'
return
end
# 新增結束
# 寫到 /etc/mail/virtusertable 及生效的動作
output
respond_to do |format|
if @vtable.update_attributes(params[:vtable])
flash[:notice] = 'Vtable was successfully updated.'
format.html { redirect_to(@vtable) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @vtable.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /vtables/1
# DELETE /vtables/1.xml
def destroy
@vtable = Vtable.find(params[:id])
# 新增始
if @vtable.user_id != current_user.id
flash[:notice] = '不可偷刪不是自己帳號的內容!'
render :text => '不可偷刪不是自己帳號的內容!'
return
end
# 新增結束
@vtable.destroy
# 寫到 /etc/mail/virtusertable 及生效的動作
output
respond_to do |format|
format.html { redirect_to(vtables_url) }
format.xml { head :ok }
end
end
# 新增始
private
def output
@filename = '/etc/mail/virtusertable'
system "> #{@filename}"
@vs = Vtable.find(:all)
@vs.each do |v|
system "echo #{v.vname}@虛擬主機名 #{v.forward} >> #{@filename}"
system "/usr/sbin/makemap hash #{@filename} < #{@filename}"
end
end
# 新增結束
end
上述最後幾行的 def output 區塊的動作,就是將 virtusertable 檔案變成空檔,然後將 vtables 的表格內容一行一行地 append 到該檔,再做 makemap 的動作生效。
(字數超過,後一篇才告一段落)