快捷搜索:

一个带完整的RBAC授权系统的rails应用(第二部分

这里先给出我们的rails利用的终极形态!(图片都是对照大年夜,请下载回来仔细看!)

第一部分已经大年夜体完成了授权系统,但纵然这样项目依然离我们心目中的微缩版维基差很远,我们必须增添更多的模块,完善其功能。

新建Lamme模块,此中point属性是用来奖励的(积分系统)

ruby script/generate scaffold Lemmatitle:string body:text point:integer

打开迁移义务,默认每个词条的奖励分是5。

class CreateLemmas5

t.timestamps

end

end

def self.down

drop_table :lemmas

end

end

新建迁移义务,继承完成积分系统。

ruby script/generate migration AddPointToUser point:integer

改动迁移义务,每个维客的初始积分为0。

class AddPointToUser0

end

def self.down

remove_column :users, :point

end

end

新建Coauthor模块,它是维基的共笔系统的根基。从数据库角度来看,它是作为User与Lamme的中心表的存在,User与Lamme经由过程它成多对多关系。也便是,一个词条可以有许多作者,一个作者能编写许多词条。在rails中实现多对多关系有两种要领 has_and_belongs_to_many与has_many :through,后者更为强大年夜,拥有给连接表应用的模型类与更多属性,命名也加倍机动直不雅准确。

ruby script/generate scaffold Coauthor user:belongs_to lemma:belongs_to activion:boolean

属性activion默认是false,它是我们为维客添加积分的一个判断标准。

class CreateCoauthorsfalse

t.timestamps

end

end

def self.down

drop_table :coauthors

end

end

我们先改动路由规则

ActionController::Routing::Routes.draw do |map|

map.resources :lemmas do |lemma|

lemma.resources :coauthors

end

map.logout '/logout', :controller => 'sessions', :action => 'destroy'

map.login '/login', :controller => 'sessions', :action => 'new'

map.register '/register', :controller => 'users', :action => 'create'

map.signup '/signup', :controller => 'users', :action => 'new'

map.resources :users

map.resource :session

map.root :lemmas

map.connect ':controller/:action/:id'

map.connect ':controller/:action/:id.:format'

end

改动Coauthor模型,添加一个措施。

class Coauthor

改动Lemma模型,完善多对多关系,并添加两个帮助措施,用来判断当前用户是否该词条的合营创作者。

class Lemma:coauthors

def contains?(user)

not contains(user).nil?

end

def contains(user)

coauthors.find_by_user_id(user)

end

end

为User模型添加以下代码,完成多对多关系。

has_many :coauthors

has_many :lemmas ,:through => :coauthors

改动lemmas_controller,完成积分系统。

class LemmasController[:show, :edit, :update, :destroy]

before_filter :new_lemma, :only => :new

def index

@lemmas = Lemma.all

end

def show;end

def new;end

def edit;end

def create

@lemma = Lemma.new params[:lemma]

if @lemma.save

#为词条的创建者添加积分。

coauthor =Coauthor.create!(:lemma => @lemma,:user => current_user,:activion => true)

coauthor.user.increment!(:point,@lemma.point) if coauthor.active?

flash[:notice] = '创建词条成功!'

redirect_to @lemma

else

render :action => "new"

end

end

def update

if @lemma.update_attributes(params[:lemma])

coauthor = Coauthor.find_by_user_id_and_lemma_id current_user.id,@lemma.id

#只为后来的编辑者添加积分。

#activation 为 true,表示在这词条上,该作者已被奖励过了!

coauthor.user.increment!(:point,@lemma.point) unless coauthor.active?

coauthor.update_attribute(:activion,true) unless coauthor.active?

flash[:notice] = '更新词条成功!'

redirect_to @lemma

else

render :action => "edit"

end

end

def destroy

@lemma.destroy

flash[:notice] = '删除词条成功!'

redirect_to lemmas_url

end

protected

def load_lemma

@lemma = Lemma.find params[:id]

end

def new_lemma

@lemma= Lemma.new

end

end

现在lemmas#index是网站的首页,因为还短缺足够的材料,是以我们照样不要动它。打开lemmas#show,让我们添加链接,让后来的维客也可以申请成为该词条的作者。

合营创作者:

删除Coauthor的所有视图,我们不必要用到它们。改动coauthors_controller,删除多余action。

class CoauthorsController:create

filter_access_to :all, :attribute_check => true

def create

if @coauthor.save

flash[:notice] = '成功加入该词条的合营创作者!'

redirect_to @lemma

else

flash[:notice] = '试图加入该词条的合营创作者掉败!'

redirect_to @lemma

end

end

def destroy

@coauthor = Coauthor.find(params[:id])

@coauthor.destroy

flash[:notice] = "成功退出该词条的合营创作者!"

redirect_to @lemma

end

protected

def load_coauthor

@lemma = Lemma.find(params[:lemma_id])

end

def new_coauthor_from_params

@coauthor = @lemma.coauthors.new(:user => current_user)

end

end

改动lemmas#new,让我们创建一个词条看看(留意删除app/views下的多余全局模板)。

用另一个帐号登录,加入成为配相助者,就可以编辑别人创建的词条。

因为现在的模块照样对照少,我们稍后再对它们进行授权节制。在第一部分中,你们也看到使用declarative authorization插件实现授权节制是何等轻松的,以是不用发急。

现在我们将实现标签系统。跟着词条的增添,我们很有需要对词条进行分类。标签在web1.0期间可能只是网页的装饰,内容的摆设,技巧的鸡肋。但在web2.0期间,标签将是全部网站内容关联体系最紧张的一环。

标签在web2.0网站中的感化如下:

内容与用户的交互:用户可以让内容付与自己的个性属性,经由过程加标签的操作,让内容变得可轮回,可梳理。大年夜量的用户-标签的交互会孕育发生化学反映,使全部网站的内容形成一个环状,把每个内容孤岛都可以串连起来。

内容的关联:经由过程人工的标注,内容本身带有了过滤后的符号意义,可以作为一个关键字来关联,也可以作为用户群的共性来关联,更可以两者结合,把用户-标签-用户的全部系统轮回使用起来。

标签的展示:标签本身作为一个浓缩的符号,具有富厚的代表意义和广泛的影响力,经由过程标签群的展示,让用户找到目标流量,让网站流量的输入和导出变得加倍紧凑,富厚而有节奏。

标签的任务:在web2.0架构中,分外是针对UGC的网站,标签不仅是内容的,照样用户的。标签站在用户和内容之间,它可以孕育发生各类各样的功能和后台关联。它的任务便是把内容和用户连起来,而怎么个连法,必要产品设计者充分的创意。

标签在web2.0网站最巨大年夜的利用便是标签云(Tag Cloud),也是我们标签系统的重点。看起来很美,但也很繁杂,但因为是在rails上实现,统统都变得很简单,一个插件足矣!

安装插件

ruby script/plugin install git://github.com/jviney/acts_as_taggable_on_steroids.git

ruby script/generate acts_as_taggable_migration

rake db:migrate

我们这个微缩版维基能利用标签的地方不多,也只有Lemma这个模块。假如是大年夜型利用,你尽可以在贴子、新闻、图片、附件、博客等等都贴上标签……

class Lemma:coauthors

def contains?(user)

not contains(user).nil?

end

def contains(user)

coauthors.find_by_user_id(user)

end

end

这样它就为Lemma添加一系列措施,常用的有:

实例措施tag_list,返回该工具的所有标签的名字的数组,它的to_s颠末改写,默认是返回用英文逗号分开的字符串。

实例措施tag_counts,返回该工具的所有标签工具的数组(很囧的命名,我还以为是返回一个数字。)

类措施find_tagged_with,返回的是被标签模型的工具数组,详细用法见下面例子,

Post.find_tagged_with("web-development, tutorial", :match_all => true)

类措施tag_counts,这个也是实例措施,不过此次是返回这个模块所关联的所有标签工具的数组。

此外,要应用tag_cloud这个赞助措施,必须在application_help这个全局赞助模块中包孕TagsHelper。不过,github给出的那个标签云的例子功能太弱,没有字体与颜色的变更,基础无法凸起它们的热门程度,仅仅是超链接的堆砌,不要也罢。我一下子供给一个功能更强大年夜的同名措施来实现标签云。

更具体的内容可以翻看其源码,那么让我们开始吧。

我们盘算在lemmas#show视图中列出该词条的所有标签,是以得改动lemmas#show action。

def show

@tags = Lemma.tag_counts

end

我们还想在视图中增添两个链接,用来动态增添与删除标签,这得在节制器添加两个action——add_tag与remove_tag。

此外,当我们点击该词条的标签云的集应时,我们盼望该链接将带我们到拥有同一个标签的词条列表中,从而使所有词条有机地联络在一路。这就又要增添一个action与视图了。改动后的节制器为:

class LemmasController[:show, :edit, :update, :add_tag,:remove_tag,:destroy]

before_filter :new_lemma, :only => :new

# filter_access_to :all

# filter_access_to [:new,:create, :edit, :update], :attribute_check => true

def tag

@lemmas = Lemma.find_tagged_with params[:id]

end

def show

@tags = @lemma.tag_counts

end

def add_tag

@lemma.tag_list.add params[:tag]

@lemma.save_tags

id = dom_id(@lemma) + "_tags"

render :update do |page|

page.replace_html id, tag_cloud(@lemma.tag_counts)

page

留意:现在先关闭lemmas的授权节制,否则无法造访。

为了,前进机能,我们平日还要用tag caching,也便是在被标签的模型的表添加一个字段cache_tag_list,那么当我们查询标签时就不再找tags表的麻烦了,直接问cache_tag_list要!

script/generate migration AddCacheTagListToLemma cache_tag_list:string

rake db:migrate

但有利必有弊,这样我们更新删除标签时,rails都直接与lemmas与taggings打交道,对tags表不闻不问,而tag表对付 tag_counts(无论是实例措施照样类措施)都异常紧张,tag_counts返回的工具数组拥有一个 count属性,它是统计某个标签在模型中呈现的次数(热门程度的又名)。而save_cached_tag_list只对cache_tag_list 处置惩罚,连save也不如(当我们删除某标签后,save会改动cache_tag_list里的字段,并删除taggings里tag_id为我们删除了的标签的ID的记录),这时只有让save_tags出马了,它会同时修正这三个表!

改动lemmas#show视图。

合营创作者:

开放分类:

_tags">

add_tag_lemma_url(@lemma),

:method => 'put',

:before => "$tag = prompt('输入要添加的标签,多个标签请用英文逗号隔开!')",

:with => "'tag=' + $tag",

:html => {:class => "adjust_tag"}

%>

remove_tag_lemma_url(@lemma),

:method => 'delete',

:before => "$tag = prompt('输入要删除的标签,多个标签请用英文逗号隔开!')",

:with => "'tag=' + $tag",

:html => {:class => "adjust_tag"}

%>

添加lemmas#tag视图。

300 %>

|

改动路由规则,包管我们上面的链接生效。

ActionController::Routing::Routes.draw do |map|

map.resources :lemmas,:member => {:add_tag => :put,:remove_tag =>:delete},:collection => {:tag => :get}do |lemma|

lemma.resources :coauthors

end

#……………………

end

着末是tag_cloud赞助措施

现在是时刻为项目加上分页功能了,安装will_paginate

git clone git://github.com/mislav/will_paginate.git vendor/plugins/will_paginate

改动lemmas#tag action

def tag

options = Lemma.find_options_for_find_tagged_with(params[:id],\

:order => "updated_at DESC").merge(:page => params[:page] ||1,:per_page =>3 )

@lemmas = Lemma.paginate(options)

end

改动对应视图

"lemma_title",:hidefocus=>"true" %>

250,:omission => "……#{link_to '全文',lemma}"%>

|

好了,接着下来我们盘算统计一下每个词条的点击率,既然有热门标签(经由过程Tag.count属性),当然有人气词条。

ruby script/generate migration AddHitsToLemma hits:integer

改动迁移义务

class AddHitsToLemma0

end

def self.down

remove_column :lemmas, :hits

end

end

履行!

rake db:migrate

我们在lemmas#show action中进行统计,并且不得本人刷屏作弊!首先我们在模型中添加一个措施

def hit!

self.class.increment_counter :hits, id

end

然后改动action

def show

@lemma.hit! unless logged_in? && @lemma.users.include?(current_user)

@tags = @lemma.tag_counts

end

假如我们翻看百度百科,就会发明一个叫“相关词条”的链接。它是基于搜索引擎实现,谋略两个词条中被搜索的关键字群的重合程度。很显然,我们单用 JOIN与LIKE去实现是异常不明智的,但acts_as_taggable_on_steroids供给了一个find_related_tags措施,返回关系慎密的标签,我们可以用它来搞个相关标签。可能还有些人对关系慎密的标签糊里糊涂,我举个例子。比如,我们有三个词条:a9vg,levelup,tgfc。a9vg有4个标签:游戏,神机,崇高饭,下限。levelup有三个标签:游戏,小白,下限。tgfc有5个标签:游戏,下限,小白,脑残,虚拟内存。我们就可以说游戏与下限的关系异常慎密,老是一路呈现,假如放宽一点,发明游戏与小白也常常搭配在一路……这有点找近义词的意味。假如我们近来注册一些邮箱,它可能要你填写你的兴趣或职业,然后自作智慧发一些与这些字眼搭边的垃圾邮件过来……嘛,扯远了,让我们完成这功能吧。>

我们先搞出一个赞助措施,用来谋略这个词条的一些标签哪一个最热门。

module LemmasHelper

def hot_tag tags

a = 0

result = nil

tags.each do |tag|

if a

>最找出这个热门标签平日和哪些标签常常一路呈现,选出排名最前的五个。

def show

@lemma.hit! unless logged_in? && @lemma.users.include?(current_user)

@tags = @lemma.tag_counts

tag = hot_tag @tags

@related_tags =Lemma.find_related_tags tag.name,:limit => 5

end

当然这样是无法运行,之前我们的tag_cloud是放在inline RJS里面,怎么说照样视图的范畴,但我们这个很显着是节制器的器械,是以我们得想个法子。着实 也不太难、include它便是!

class ApplicationController

视图中添加

你可以感兴趣的标签:

:tag, :id => tag.name },\

:style => tag_style(@related_tags,tag.name) %>

看到这些多标签,我想是否要做些SEO优化呢。现在它们都是放在通俗的链接中,威力太小,放在keywords的meta标签中效果应该会增添两三倍。同样,我们先做赞助措施,不宜在视图中直接写逻辑。

module LayoutHelper

#……………………

def keywords *args

content_for(:keywords){ args }

end

def description *args

content_for(:description){ args }

end

end

在lemmas#show 视图中添加

120)) %>

然后在全局模板的头部添加对应代码。

" />

" />

#……………………

#……………………

翻看网页的源码,发明成功了!

但我们照样感觉在视图上写得太多逻辑了,再对它们做些封装。

module LemmasHelper

def seo_meta lemma

unless lemma.blank?

keywords h(lemma.tag_list.to_s)

description h(lemma.title + "——"+ truncate(lemma.body ,:length => 120))

end

end

#………………

end

这样在视图中就可以很简洁搞定了!

现在我们动一动首页吧,那里照样一片处女地。平日首页上查询异常多,而且很多排行,我们的利用也是如斯。我们得在模型中添加一些措施,以达到Skinny Controller, Fat Model的功效。

在User模型中添加

named_scope :worthy,:limit => 10,:select => "id,login,point",:order =>"point DESC"

在Lemma模型中添加

named_scope :reward, :select => "id,title,point",:limit=> 10,:order =>"point DESC"

named_scope :latest, :select => "id,title,updated_at",:limit=> 10,:order =>"updated_at DESC"

named_scope :hot, :select => "id,title,hits",:limit=> 10,:order =>"hits DESC"

改动首页

最新词条

热门词条

高分词条

供献榜

好了,网站的功能基础就完成了。我们可以专注搞lemma模块的授权节制了。改动授权规则。

authorization do

role :guest do

has_permission_on :users, :to => [:read_index,:create]

has_permission_on :lemmas, :to => :read

end

role :wikier do

includes :guest

has_permission_on :users, :to => [:read_show,:update] do

if_attribute :id => is {user.id}

end

has_permission_on:coauthors, :to => :create

has_permission_on:lemmas, :to => [:create,:add_tags,:remove_tags]

has_permission_on:lemmas, :to => :update do

if_attribute :users => contains {user}

end

end

role :peace_maker do

includes :wikier

has_permission_on :users, :to => :read_show

has_permission_on :lemmas, :to => :update

end

role :providence_breaker do

has_permission_on [:users,:lemmas,:coauthors], :to =>:manage

end

end

privileges do

privilege :manage, :includes => [:create, :read, :update, :delete,:add_tags,:remove_tags]

privilege :read, :includes => [:index, :show, :tag]

privilege :read_index, :includes => :index

privilege :read_show, :includes => :show

privilege :create, :includes => :new

privilege :add_tags,:includes => :add_tag

privilege :remove_tags,:includes => :remove_tag

privilege :update, :includes => :edit

privilege :delete, :includes => :destroy

end

这个有点像视图中的层叠样式表(CSS),能承袭能覆盖。

和其他授权插件一样,在视图中都是对链接下手。

♠最新词条

"创建于:#{lemma.created_at.to_s(:db)}" %>

♣热门词条

"点击数:#{lemma.hits}" %>

♥待完善词条

"赏格分:#{lemma.point}"%>

♦供献排行榜

">

"myself") %>

改动lemmas#show。

#……………………

#………………………………

add_tag_lemma_url(@lemma),

:method => 'put',

:before => "$tag = prompt('输入要添加的标签,多个标签请用中文逗号隔开!')",

:with => "'tag=' + $tag",

:html => {:class => "adjust_tag"} \

if permitted_to? :add_tags,:lemmas

%>

remove_tag_lemma_url(@lemma),

:method => 'delete',

:before => "$tag = prompt('输入要删除的标签,多个标签请用中文逗号隔开!')",

:with => "'tag=' + $tag",

:html => {:class => "adjust_tag"} \

if permitted_to? :remove_tags,:lemmas

%>

#…………………………………………

#……………………………………………………

这里讲一些细节(请对比授权规则),对付那些自定义actions(即非restful actions),它们只能一个action对应一个特权,如:

privilege :add_tags,:includes => :add_tag

privilege :remove_tags,:includes => :remove_tag

不能够像其他restful 特权那样对应两个或多个action。下面这个是差错的:

privilege :abjust_tag,:includes => [:add_tag,:remove_tag]

另,这些自定义特权向上组合(即与其他特权组成一个范围更广的特权),除了取名为create,read,update,delete,manage,否则一切无效!下面代码的着末一行是差错的。

privilege :add_tags,:includes => :add_tag

privilege :remove_tags,:includes => :remove_tag

privilege :inoperative,:includes => [:add_tags,:remove_tags]

再次,假如这些链接的授权造访,假如不用进行属性反省,我们直接permitted_to? :add_tags,:lemmas就可以了,表示对Lamme这种资本,而不特定到某个个体。我们在第一部分提过了,这叫做粗颗粒的(授权)造访节制。像要编辑词条特定到某个详细的工具,就要用细颗粒的造访节制。

着末一个,为了不用在输入中文标签的时刻切换英文逗号,我们改动了其距离号,在environment.rb的最下边添加:

TagList.delimiter = ","

接着是new与edit视图了,为了Don't Repeat Yourself!我们添加一个_form.html.erb。

2 %>

好了,现在改动new视图:

"lemmas/form",:locals => {:button_name => "创建"}%>

改动update视图:

"lemmas/form",:locals => {:button_name => "更新"} %>|

改动tag视图,增添SEO支持

"lemma_title",:hidefocus=>"true" %>

250,:omission => "……#{link_to '全文',lemma}"%>

|

改动_user_bar.html.erb

#………………………………

#………………………………

改动users#edit视图,让只有权限最高的人才能改动别人的角色

#…………………………

"请选择",:selected => 0} %>

#………………………………

着末让我们见识一下此插件引以为荣的图形化界面吧。添加授权规则。

role :providence_breaker do

has_permission_on [:users,:lemmas,:coauthors], :to =>:manage

has_permission_on :authorization_rules, :to => :manage

has_permission_on :authorization_usages, :to => :manage

end

_user_bar.html.erb增添链接

不过BUG太多了,每个游览器都不一样,IE逝世得最惨!或许是rails进级太快,declarative authorization插件跟不上吧。等插件作者更新吧!

这是插件作者 Steffen Bartsch 给出的效果图

您可能还会对下面的文章感兴趣: