{"id":22022701,"url":"https://github.com/cj/sinatra-can","last_synced_at":"2025-05-07T07:22:49.979Z","repository":{"id":2346677,"uuid":"3309306","full_name":"cj/sinatra-can","owner":"cj","description":"CanCan wrapper for Sinatra.","archived":false,"fork":false,"pushed_at":"2011-10-15T01:35:05.000Z","size":100,"stargazers_count":3,"open_issues_count":0,"forks_count":8,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-29T11:13:57.595Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cj.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-01-30T21:53:26.000Z","updated_at":"2018-04-25T21:56:48.000Z","dependencies_parsed_at":"2022-08-26T12:52:01.226Z","dependency_job_id":null,"html_url":"https://github.com/cj/sinatra-can","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cj%2Fsinatra-can","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cj%2Fsinatra-can/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cj%2Fsinatra-can/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cj%2Fsinatra-can/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cj","download_url":"https://codeload.github.com/cj/sinatra-can/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227284666,"owners_count":17758437,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-30T06:22:28.249Z","updated_at":"2024-11-30T06:22:28.749Z","avatar_url":"https://github.com/cj.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"Sinatra::Can\n============\n\nSinatra::Can is a lightweight wrapper for the CanCan authorization library. It contains a partial implementation of CanCan's Rails helpers, but in Sinatra.\n\nCheck out CanCan if you don't know it: https://github.com/ryanb/cancan/\n\n## Installing\n\nTo install this gem, just use the gem command:\n\n    gem install sinatra-can\n\nTo use it in your project, just require it:\n\n    require 'sinatra/can'\n\n## Abilities\n\nAbilities are defined using a block just like with Sinatra. Here's the canonical example, which gives permission for admin users to manage and for non-admins to read:\n\n    ability do |user|\n      can :manage, :all if user.admin?\n      can :read, :all\n    end\n\nYou can use regular CanCan syntax, since our gem is just a wrapper:\n\n    ability do |user|\n      if user.is_admin?\n        can :kick, User do |victim|\n          !victim.is_admin?\n        end\n      end\n    end\n\nAlternatively, you can use a class named Ability, which is useful if you're porting a project from Rails to Sinatra. That's the regular CanCan way:\n\n    class Ability\n      include CanCan::Ability\n\n      def initialize(user)\n        can :manage, :all if user.admin?\n        can :read, :all\n      end\n    end\n\n## Current User\n\nYou can pass the current user with a simple block:\n\n    user do\n      User.find(:id =\u003e session[:id])\n    end\n\n## Checking Abilities\n\nThe can? method receives an action and an object as parameters and checks if the current user is allowed, as declared in the Ability. This method is a helper that can be used inside blocks:\n\n    can? :destroy, @project\n    cannot? :edit, @project\n\nAnd in views too:\n\n    \u003c% if can? :create, Project %\u003e\n      \u003c%= link_to \"New Project\", new_project_path %\u003e\n    \u003c% end %\u003e\n\n## Authorizing\n\nAuthorizing in CanCan is very neat. You just need a single line inside your routes:\n\n    def '/admin' do\n      authorize! :admin, :all\n\n      haml :admin\n    end\n\nIf the user isn't authorized, your app will return a RESTful 403 error, but you can also instruct it to redirect to other pages by defining this setting at your Sinatra configuration.\n\n    set :not_auth, '/login'\n\nOr directly in the authorize! command itself:\n\n    authorize! :admin, :all, :not_auth =\u003e '/login'\n\nSinatra lacks controllers, but you can use \"before\" blocks to restrict groups of routes with wildcards (or even regular expressions). In this case you'll only be able to access the pages under /customers/ if your user is authorized to \":manage\" some \"Customers\".\n\n    before '/customers/*' do\n      authorize! :manage, Customers\n    end\n\n## Conditions\n\nThere is a built-in condition called :can that can be used in your blocks. It returns 403 when the user has no access. It basically replaces the authorize! method.\n\n    get '/admin', :can =\u003e [ :admin, :all ] do\n      haml :admin\n    end\n\n## Load and Authorize\n\nload_and_authorize is one of CanCan's greatest features. It will, if applicable, load a model based on the :id parameter, and authorize, according to the HTTP Request Method.\n\nThe usage with this Sinatra adapter is a bit different and way simpler, and it's implemented from scratch. Since Sinatra is based on routes (as opposed to controllers + methods), you need to tell which model you want to use. It will guess the action (:view, :create, etc) using the HTTP verb, and an 'id' parameter to load the model.\n\nIt is compatible with ActiveRecord, DataMapper and Sequel.\n\nHere's the syntax:\n\n    get '/projects/:id' do\n      load_and_authorize! Project\n\n      # It's loaded now.\n      @project.name\n    end\n\nThere's also a handy condition:\n\n    get '/projects/:id', :model =\u003e Project do\n      @project.name\n    end\n\nAuthorization happens right after autoloading, and depends on the HTTP verb. Here's the CanCan actions for each verb:\n\n - :list (get without an :id)\n - :view (get)\n - :create (post)\n - :update (put)\n - :delete (delete)\n\nSo, for a model called Projects, you can define your Ability like this, for example:\n\n    ability do |user|\n      can :list, Project\n      can :view, Project\n      can :create, Project if user.is_manager?\n      can :update, Project if user.is_admin?\n      can :delete, Project if user.is_admin?\n    end\n\n## Modular Style\n\nTo use this gem in Modular Style apps, you just need to register it:\n\n    class MyApp \u003c Sinatra::Base\n      register Sinatra::Can\n\n      ...\n    end\n\n## Changing Defaults\n\nIt's easy to change the default ability class. Our example looks a lot like the CanCan one, but we're doing it inside a before do...end method for flexibility: this way you can even associate different ability classes to different routes.\n\n    before do\n      @current_ability ||= ::MyAbility.new(current_user)\n    end\n\n## Example App\n\nHere's here's an example app using Modualar-style.\n\nTo test, pass your user name via the ?user= query string. `/secret?user=admin` should be accessible, but `/secret?user=someone_else` should be off limits.\n\n    require 'rubygems'\n    require 'sinatra'\n    require 'sinatra/can'\n\n    class MyApp \u003c Sinatra::Base\n      register Sinatra::Can\n\n      ability do |user|\n        can :read, :secret if user == \"admin\"\n      end\n\n      user do\n        params[:user]\n      end\n\n      error 403 do\n        'not authorized'\n      end\n\n      get '/secret' do\n        authorize! :read, :secret\n        'you can read it'\n      end\n    end\n\n    use MyApp\n\n## Future\n\nCanCan provides a lot of helpers, so this is just the start. The code is quite simple and any help is welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcj%2Fsinatra-can","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcj%2Fsinatra-can","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcj%2Fsinatra-can/lists"}