iT邦幫忙

DAY 7
10

Rails 的簡單任務系列 第 7

[RoR] 多人用虛擬轉址信箱的建置(2)

第六日已建立了虛擬轉址信箱的機制,而今天是再結合第三日及第五日的內容,讓 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 的動作生效。
(字數超過,後一篇才告一段落)


上一篇
[RoR] 多人用虛擬轉址信箱的建置(1)
下一篇
[RoR] 多人用虛擬轉址信箱的建置(2)(續)
系列文
Rails 的簡單任務33

1 則留言

0
gric
iT邦高手 1 級 ‧ 2009-03-13 21:34:56

謝謝分享咯!

我要留言

立即登入留言