Skip to content

Instantly share code, notes, and snippets.

@chipiga
Created September 1, 2010 14:42
Show Gist options
  • Save chipiga/560771 to your computer and use it in GitHub Desktop.
Save chipiga/560771 to your computer and use it in GitHub Desktop.
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
can :read, [Project, News, Article, Page], :state => 'published'
if user.roles?(:admin)
can :manage, :all
else
if user.roles?(:user)
end
if user.roles?(:author)
can :index, [Project, News, Article, Page], ["(state = 'published') OR (user_id = ?)", user.id]
can :show, [Project, News, Article, Page] # TODO redo this gap!
can :read, [Asset, Vcard], :user_id => user.id
can :create, [Project, News, Article, Page, Asset, Vcard]
can :update, [Project, News, Article, Page, Asset, Vcard], :user_id => user.id
end
if user.roles?(:moderator)
can :read, [Project, News, Article, Page, Asset, Vcard]
can :update, [Project, News, Article, Page, Asset, Vcard]
end
end
end
end
require 'spec_helper'
require 'cancan/matchers'
describe Ability do
context "as a guest" do
let(:user) { User.new }
let(:ability) { Ability.new(user) }
context "for Project" do
it "should be able to read published projects" do
ability.should be_able_to(:read, Factory.build(:published_project))
end
it "should not be able to read draft projects" do
ability.should_not be_able_to(:read, Factory.build(:draft_project))
end
it "should not be able to create project" do
ability.should_not be_able_to(:create, Project)
end
it "should not be able to update project" do
ability.should_not be_able_to(:update, Factory.build(:project))
end
it "should not be able to destroy project" do
ability.should_not be_able_to(:destroy, Factory.build(:project))
end
end
end
context "as a user" do
let(:user) { Factory.create(:user) }
let(:ability) { Ability.new(user) }
context "for Project" do
it "should be able to read published projects" do
ability.should be_able_to(:read, Factory.build(:published_project))
end
it "should not be able to read draft projects" do
ability.should_not be_able_to(:read, Factory.build(:draft_project))
end
it "should not be able to create project" do
ability.should_not be_able_to(:create, Project)
end
it "should not be able to update project" do
ability.should_not be_able_to(:update, Factory.build(:project))
end
it "should not be able to destroy project" do
ability.should_not be_able_to(:destroy, Factory.build(:project))
end
end
end
context "as an author" do
let(:user) { Factory.create(:author_user) }
let(:ability) { Ability.new(user) }
context "for Project" do
it "should be able to read published projects" do
ability.should be_able_to(:read, Factory.build(:published_project))
end
pending "should not be able to read all draft projects" do
# ability.should_not be_able_to(:read, Factory.build(:draft_project))
ability.should_not be_able_to(:index, Factory.build(:draft_project))
ability.should_not be_able_to(:show, Factory.build(:draft_project))
end
it "should be able to read own draft projects" do
# ability.should be_able_to(:read, Factory.build(:draft_project, :user => user))
ability.should be_able_to(:index, Factory.build(:draft_project, :user => user))
ability.should be_able_to(:show, Factory.build(:draft_project, :user => user))
end
it "should be able to create project" do
ability.should be_able_to(:create, Project)
end
it "should not be able to update any project" do
ability.should_not be_able_to(:update, Factory.build(:project))
end
it "should be able to update own project" do
ability.should be_able_to(:update, Factory.build(:project, :user => user))
end
it "should not be able to destroy project" do
ability.should_not be_able_to(:destroy, Factory.build(:project, :user => user))
end
end
end
context "as a moderator" do
let(:user) { Factory.create(:moderator_user) }
let(:ability) { Ability.new(user) }
context "for Project" do
it "should be able to read all projects" do
ability.should be_able_to(:read, Factory.build(:project))
end
it "should_not be able to create project" do
ability.should_not be_able_to(:create, Project)
end
it "should be able to update any project" do
ability.should be_able_to(:update, Factory.build(:project))
end
it "should not be able to destroy project" do
ability.should_not be_able_to(:destroy, Factory.build(:project))
end
end
end
context "as an admin" do
let(:user) { Factory.create(:admin_user) }
let(:ability) { Ability.new(user) }
context "for Project" do
it "should be able to read all projects" do
ability.should be_able_to(:read, Factory.build(:project))
end
it "should be able to create project" do
ability.should be_able_to(:create, Project)
end
it "should be able to update any project" do
ability.should be_able_to(:update, Factory.build(:project))
end
it "should be able to destroy project" do
ability.should be_able_to(:destroy, Factory.build(:project))
end
end
end
end
# Add paternity (authorship) link
module Platform
module Controllers
module Paternity
extend ActiveSupport::Concern
included do
before_filter :build_resource, lambda{ resource.user = current_user }, :only => :create
end
module InstanceMethods
end
module ClassMethods
end
end
end
end
share_examples_for "paternity" do
it "should set authorship for resource" do
resource.class.stub(:new) { resource }
resource.should_receive(:user=).with(controller.current_user)
post :create, :project => {}
end
end
class Project < ActiveRecord::Base
belongs_to :user
scope :published, where(:state => 'published')
scope :draft, where(:state => 'draft')
scope :ordered, order('priority DESC').order('id DESC')
# default_scope ordered
after_initialize lambda { self.started_at ||= Time.zone.now } # Date.today
validates :name, :aim, :description, :started_at, :presence => true
# attr_accessible
has_friendly_id :name, :use_slug => true
include Platform::Models::Slug
include Platform::Models::Tag
def news
@news ||= News.tagged_with(name)
end
def articles
@articles ||= tag_list.map { |t| Article.where('title LIKE ?', "%#{t}%") }.flatten.uniq
end
def assets
@assets ||= Asset.tagged_with(name)
end
# TODO redo to connect through categories?
def vcards
family_name, given_name = name.split(' ')
@vcards ||= Vcard.where('agent_id IS NOT NULL').where(:family_name => family_name, :given_name => given_name)
@vcards = Vcard.where('agent_id IS NOT NULL').where("? LIKE #{db_concat('%', :family_name, '%')}", name) if @vcards.blank?
# @vcards ||= Vcard.where('agent_id IS NOT NULL').where("? = CONCAT(family_name, ' ', given_name)", name) # mysql only
# @vcards = Vcard.where('agent_id IS NOT NULL').where("? LIKE CONCAT('%', family_name, '%')", name) if @vcards.blank? # mysql only
@vcards
end
# TODO move to gem || plugin ?
private
def db_concat(*args)
case ActiveRecord::Base.connection.adapter_name.downcase
when 'mysql' then "CONCAT(#{quote_args(*args).join(', ')})"
when 'sqlite', 'sqlite3', 'postgresql' then quote_args(*args).join(' || ')
else raise 'Sorry. Current adapter is not supported yet!'
end
end
def quote_args(*args)
args.map do |arg|
case arg
when Symbol then ActiveRecord::Base.connection.quote_column_name(arg)
else ActiveRecord::Base.connection.quote(arg)
end
end
end
end
require 'spec_helper'
describe Project do
let(:project) { Factory.create(:project) }
context "#news" do
let(:news) { Factory.create(:news) }
it "should have news" do
project.should respond_to(:news)
end
it "should return collection of related news connected through tags" do
news.tag_list = project.name; news.save
project.news.should eq([news])
end
end
context "#articles" do
let(:article) { Factory.create(:article) }
it "should have articles" do
project.should respond_to(:articles)
end
it "should return collection of related articles connected through tags" do
project.tag_list = article.title; project.save
project.articles.should eq([article])
end
end
context "#assets" do
let(:asset) { Factory.create(:attachment) }
it "should have assets" do
project.should respond_to(:assets)
end
it "should return collection of related assets connected through tags" do
asset.tag_list = project.name; asset.save
project.assets.should eq([asset])
end
end
context "#vcards" do
it "should have vcards" do
project.should respond_to(:vcards)
end
pending "TODO change logic"
end
end
class ProjectsController < InheritedResources::Base
respond_to :html
has_scope :tag
include Platform::Controllers::Slug
include Platform::Controllers::Auth
include Platform::Controllers::Paternity
include Platform::Controllers::Paginate
end
require 'spec_helper'
require 'controllers/shared/paternity'
require 'controllers/shared/slug'
describe ProjectsController do
def mock_project(stubs={})
@mock_project ||= mock_model(Project, stubs).as_null_object
end
context "paternity" do
let(:resource) { mock_project }
before(:each) { sign_in Factory.create(:author_user) }
it_should_behave_like "paternity"
end
context "slug" do
let(:resource) { Factory.create(:published_project) }
it_should_behave_like "slug"
end
end
# Check current slug is the best
module Platform
module Controllers
module Slug
extend ActiveSupport::Concern
included do
before_filter :ensure_current_resource_url, :only => :show
end
module InstanceMethods
protected
def ensure_current_resource_url
redirect_to resource, :status => :moved_permanently unless resource.friendly_id_status.best?
end
end
module ClassMethods
end
end
end
end
share_examples_for "slug" do
it "should redirect to correct URL" do
get :show, :id => "#{resource.id}-wrong-slug"
response.should redirect_to(controller.polymorphic_url(resource))
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment