The Rails Way - Namespaces - ruby-on-rails

I have a question about how to do something "The Rails Way". With an application that has a public facing side and an admin interface what is the general consensus in the Rails community on how to do it?
Namespaces, subdomains or forego them altogether?

There's no real "Rails way" for admin interfaces, actually - you can find every possible solution in a number of applications. DHH has implied that he prefers namespaces (with HTTP Basic authentication), but that has remained a simple implication and not one of the official Rails Opinions.
That said, I've found good success with that approach lately (namespacing + HTTP Basic). It looks like this:
routes.rb:
map.namespace :admin do |admin|
admin.resources :users
admin.resources :posts
end
admin/users_controller.rb:
class Admin::UsersController < ApplicationController
before_filter :admin_required
# ...
end
application.rb
class ApplicationController < ActionController::Base
# ...
protected
def admin_required
authenticate_or_request_with_http_basic do |user_name, password|
user_name == 'admin' && password == 's3cr3t'
end if RAILS_ENV == 'production' || params[:admin_http]
end
end
The conditional on authenticate_or_request_with_http_basic triggers the HTTP Basic auth in production mode or when you append ?admin_http=true to any URL, so you can test it in your functional tests and by manually updating the URL as you browse your development site.

In some smaller applications I don't think you need to separate the admin interface. Just use the regular interface and add admin functionality for logged in users.
In bigger projects, I would go with a namespace. Using a subdomain doesn't feel right to me for some reason.

Thanks to everyone that answered my question. Looks like the consensus is to use namespaces if you want to as there is no DHH sponsored Rails Way approach. :)
Again, thanks all!

Its surely late for a reply, but i really needed an answer to this question: how to easily do admin areas?
Here is what can be used these days: Active Admin, with Ryan Bates's great intro.

Related

How to integrate frontend and admin theme together in ruby on rails

I have an application with admin in ruby on rails. Now I need to add front-end in that application. But I don't know how ingrate with both in a single application.
You can create an "admin" area pretty simply once you know how. It all comes down to namespaces, specifically:
#config/routes.rb
namespace :admin do
# Sets up "/admin"
root "application#index"
end
Namespaces are essentially "folders", which also influence the names of your Rails classes (for example, your controller class names).
This means you'll be able to use the following:
#app/controllers/admin/application_controller.rb
class Admin::ApplicationController < ActionController::Base
layout :admin
def index
#do stuff here
end
end
Your models will remain as they are now (no need to make them admin namespaced).
--
The above code should give you the ability to access yoururl.com/admin and have a controller/action to work with. Of course, this negates the fact you're going to have to populate this area with data & controller actions; it all works much similarly to a "standard" rails app once you get it working.
You'll want to check out these helpful resources:
ActiveAdmin gem
RailsAdmin gem
RubyToolbox Admin gems
Railscasts Admin tutorial:

Adding subdomain for different user types

I am pretty new to Rails and most of my knowledge depends on tutorials :)
So, I followed this http://www.railstutorial.org tutorial and created really good site but now I run into a problem. For my users I have a special column in my database which shows which type of user he is. For example I have column 'student' which is 'true' if user is student and 'false' if he's not.
Now I would like to create a subdomain for students. So, when student wants to sign up or sign in he would be transferred to www.student.mysite.com instead of www.mysite.com.
How can I accomplish that?
Thank you :)
There are a number of ways to do this, specifically you'll be interested in looking up multi-tenancy in respect to rails
--
Multi Tenancy
Whilst multi tenancy is typically the definition of having multiple databases / assets (one for each user), however, as it's ridiculously difficult to get this working in rails (something we're currently working on), you can use the principle with a single stack of data
There are several tutorials on how to achieve this with Rails here:
Basecamp-style subdomains by DHH (although looks like the post is down)
Multitenancy with PostgreSQL (Railscasts)
Apartment Gem (achieving multi tenancy on Rails)
Although this is not directly related to your question, most of the "multi tenancy" questions
are typically based on "how do I create different subdomains for my users"
--
Subdomains
The basis of subdomains on Rails is to capture the request, and route it to the correct controller. We've managed to achieve that using the following setup:
#config/routes.rb
constraints Subdomain do #-> lib/subdomain.rb & http://railscasts.com/episodes/221-subdomains-in-rails-3
#Account
namespace :accounts, path: "" do #=> http://[account].domain.com/....
#Index
root to: "application#show"
end
end
#lib/subdomain.rb
class Subdomain
def self.matches?(request)
request.subdomain.present? && request.subdomain != 'www'
end
end
This will give you the ability to do the following:
#app/controllers/accounts/application_controller.rb
class Account::ApplicationController < ActionController::Base
before_action :set_account
def show
##account set before_action. If not found, raises "not found" exception ;)
end
private
#Params from Subdomain
def set_account
params[:id] ||= request.subdomains.first unless request.subdomains.blank?
#account = Account.find params[:id]
end
end
Ideally, we'd love to handle this in the middleware, but as it stands, this is what we've got!
This will give you the ability to call the data you need from the #account variable:
#app/views/accounts/application/show.html.erb
<%= #account.name %>

What are the best practices for authorization?

Situation: rails 3.2 app with a demo period, after which users must start paying for the service.
Question: If a user does not add a payment method, or does not choose a payment plan, what is the recommended way of restricting user access to the 'paid' part of the web app?
I need something that sorts users as follows:
if user.admin? || user.in_demo || user.has_all_payment_data
# carry on
elsif user.should_add_payment_method
# send them to add payment method page
elsif user.should_choose_plan
# send them to add plan
else
# redirect to home page or whatever
end
I've started off with a before_filter on the application controller that checks the payment status of the user on every request and redirects them accordingly (skipping this in places like the homepage/profile editing etc.), but I'm thinking there must be a better way, as it's rapidly getting too complicated and it just feels wrong having all that complexity in the application controller. I've been looking at user roles libraries like cancan but I can't find anything that fits.
There is a post by Jonas Nicklas (creator of Capybara and CarrierWave) in which he explains in some detail how to take a simpler approach than CanCan's. His approach is based on an additional plain Ruby class for each model you want to create authorization rules for.
Simple authorization in Ruby on Rails apps (Elabs blog)
They have offloaded that solution into a gem named Pundit, but it really seems simple enough to be able to implement from scratch.
Pundit gem (GitHub)
I would suggest a before_filter in the application controller, then using skip_filter in individual controllers to bypass it for actions that non-paid users can access, e.g:
class ApplicationController < ActionController::Base
before_filter :check_payment
...
end
class UserController < ApplicationController
skip_filter :check_payment, :only => [:login, :logout, ...]
...
end
This keeps the access contained to the relevant controllers, rather than needing an increasingly large :except => ... on the filter itself.

Alternative for CanCan? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I use rspec, devise and cancan at the moment. To be honest, I find cancan to be very confusing and I am encountering a lot difficulties in picking it up and using it effectively. The docs are not very in depth making this extremely difficult for me to debug (check my past questions).
Is there an alternative to CanCan that's also easily integratable in the other tools I am using?
As of early 2014, Pundit is a popular alternative to CanCan (and the successor CanCanCan). Pundit matches each controller with a policy object. Unlike CanCan, there's no central rule file for all access control. It's simpler than CanCan. There's an example app from the RailsApps project:
Rails Pundit Example
I've also written a tutorial on Rails Authorization with Pundit.
Another alternative is the Authority gem from Nathan Long. All your rules logic goes in Ruby classes called "authorizers" that are associated with models.
Some guys are continuing the development of cancan. Check it out:
https://github.com/CanCanCommunity/cancancan
For the same reason i've done this: http://mcasimir.github.com/checkin/.
Checkin is an authorization gem that is independent from the role/authentication library you use.
You can express even complex rules rather simply with a declarative/cascading permissions DSL.
I found it very handy. The debug is also supported via the explain method that will log the authorization process on every request.
Here are some of the features:
Handy DSL to define roles and permissions with a declarative approach
Check authorization for CRUD operations automatically
Standard way to rescue from Authorization errors
Authorization subject decoupled from model (compatible with any autentication system)
Role-based authorization decoupled from role system (compatible with any role
system)
Decorator for current_user and other subject objects
Scoped authorization rules
Cascading authorization rules
Simple: even complex authorization behaviour is understandable at glimpse and
easily predictable
Support for controller based mass assignment protection
Here is a very simple example of the DSL:
class UserSubject < Checkin::Subject
role :guest, :alias => :anonymous do
!subject_model
end
role :logged_in, :alias => [:connected] do
!!subject_model
end
role :owner, :require => [:logged_in], :method => :own do |object|
object && ( object.respond_to?(:author) && ( subject_model == object.author ) ) || ( object.respond_to?(:owner) && ( subject_model == object.owner ) )
end
role :administrator, :require => :logged_in, :alias => :admin do
subject_model.has_role?(:administrator)
end
#
# Permissions
#
permissions :for => :comments do
allow :administrators
allow :logged_in, :to => [:create]
deny
end
# Admin
scope :admin do
permissions do
allow :administrators
allow :owners, :to => [:edit, :update]
deny
end
end
end
Checking roles and permissions:
subject = UserSubject.new(User.first, :scope => :admin)
subject.logged_in?
subject.guest?
subject.own?(Post.first)
subject.can_edit?(Post.first)
I apologize for being so wordy.
I found https://github.com/stffn/declarative_authorization to be rather complete. And it's logical to use.
Sounds like Pundit may be coming up strong. It has a less 'magic', more straightforward approach.
https://github.com/elabs/pundit
I am currently exploring Heimdallr. The one feature it has that most of these cancan alternatives don't are restricted scopes for index actions.
You also might want to check out this "ultra lite authorization library" - six
Check TheRole gem. very interesting alternative for cancan
I'd recommend Action Access, it's much simpler and straightforward, has seamless integration with Rails and it's very lightweight. It boils down to this:
class ArticlesController < ApplicationController
let :admin, :all
let :user, [:index, :show]
# ...
end
This will automatically lock the controller, allowing admins to access every action, users only to show or index articles and anyone else will be rejected and redirected with an alert.
If you need more control, you can use not_authorized! inside actions to check and reject access.
This makes controllers to be self contained, everything related to the controller is within the controller. This also makes it very modular and avoids leaving forgotten trash anywhere else when you refactor.
It's completely independent of the authentication system and it can work without User models or predefined roles. All you need is to set the clearance level for the current request:
class ApplicationController < ActionController::Base
def current_clearance_level
session[:role] || :guest
end
end
You may return whatever your app requires, like current_user.role for example.
It also bundles a set of handy model additions that allow to extend user models and do things like:
<% if current_user.can? :edit, :article %>
<%= link_to 'Edit article', edit_article_path(#article) %>
<% end %>
Here :article refers to ArticlesController, so the link will only be displayed if the current user is authorized to access the edit action in ArticlesController. It supports namespaces too.
It allows to lock controllers by default, customize the redirection path and the alert message, etc. Checkout the documentation for more.
There's also Consul.
You create a Power class with methods that return only those objects the user has access to, instead of loading objects and check permissions on them. Talk by the author.

Backend administration in Ruby on Rails

I'd like to build a real quick and dirty administrative backend for a Ruby on Rails application I have been attached to at the last minute. I've looked at activescaffold and streamlined and think they are both very attractive and they should be simple to get running, but I don't quite understand how to set up either one as a backend administration page. They seem designed to work like standard Ruby on Rails generators/scaffolds for creating visible front ends with model-view-controller-table name correspondence.
How do you create a admin_players interface when players is already in use and you want to avoid, as much as possible, affecting any of its related files?
The show, edit and index of the original resource are not usuable for the administrator.
I think namespaces is the solution to the problem you have here:
map.namespace :admin do |admin|
admin.resources :customers
end
Which will create routes admin_customers, new_admin_customers, etc.
Then inside the app/controller directory you can have an admin directory. Inside your admin directory, create an admin controller:
./script/generate rspec_controller admin/admin
class Admin::AdminController < ApplicationController
layout "admin"
before_filter :login_required
end
Then create an admin customers controller:
./script/generate rspec_controller admin/customers
And make this inhert from your ApplicationController:
class Admin::CustomersController < Admin::AdminController
This will look for views in app/views/admin/customers
and will expect a layout in app/views/layouts/admin.html.erb.
You can then use whichever plugin or code you like to actually do your administration, streamline, ActiveScaffold, whatever personally I like to use resourcecs_controller, as it saves you a lot of time if you use a REST style architecture, and forcing yourself down that route can save a lot of time elsewhere. Though if you inherited the application that's a moot point by now.
Do check out active_admin at https://github.com/gregbell/active_admin.
I have used Streamlined pretty extensively.
To get Streamline working you create your own controllers - so you can actually run it completely apart from the rest of your application, and you can even run it in a separate 'admin' folder and namespace that can be secured with .
Here is the Customers controller from a recent app:
class CustomersController < ApplicationController
layout 'streamlined'
acts_as_streamlined
Streamlined.ui_for(Customer) do
exporters :csv
new_submit_button :ajax => false
default_order_options :order => "created_at desc"
list_columns :name, :email, :mobile, :comments, :action_required_yes_no
end
end
Use https://github.com/sferik/rails_admin.

Resources