I have added the gem 'acts_as_tenant' to my Rails app.
I have set the following in the application controller:
set_current_tenant_by_subdomain(:tenant, :subdomain)
I have also added columns of information to the Tenants table. For instance the statuscode_id for a 'closed' status. In the Request model, I would like to scope using that column.
Something like this:
scope :closed, where(:statuscode_id => Tenant.find(current_tenant.id).request_closed)
But, current_tenant isn't working.
What can I use to get the id of the current tenant?
Thanks!
All you've done so far is say that the subdomain will be used to define the tenant. In order to restrict the tenant to only see their data you need to define this in the model.
You need to add acts_as_tenant(:tenant) to your Request model. You will also need a tenant_id column in the database for this table.
Once you've done this, the gem will take care of the rest and all your database access will automatically take care of restricting access by tenant. e.g. Request.all will use default scope behind the scenes to restrict to only the requests owned by that tenant.
Please see ErwinM/acts_as_tenant for more information on this.
Related
Background
I have a multi-tenant Rails application which uses the Apartment gem to switch schema depending on their subdomain when they login. The User and Account entities are in the public schema. All of the other related entities are in the account specific schema.
Question
When a new user signs up, the User and Account records are created during the initial form post (i.e., in RegistrationsController#create).
However, I would like to create other records at this time (e.g, a Family record), but the account specific schema hasn't been created yet and the context hasn't switched, so if I do something like this:
#resource.create_family(name: #resource.last_name)
The Family record will be incorrectly created in the public schema.
Devise lets you specify a after_sign_up_path_for value, so I was thinking of maybe creating a custom action in the FamiliesController that does the work of creating new record, but that seems kind of kludgy and non RESTful:
def after_sign_up_path_for(resource)
# root_url(:subdomain => resource.account.subdomain)
family_autocreate_url(:subdomain => resource.account.subdomain, :query => resource.last_name)
end
What's the right way to do this?
(Note: the schema context isn't switched until I redirect to a URL with the account specific subdomain. Hence the thought of doing it )
I currently have two roles in my system, the defaults, 'User' and 'Admin'.
I would like to add a new role called 'Supplier'.
At the moment the supplier role needs to be the same as a normal user. I have 'frontend' profile edit page. The only difference between the user and supplier is that the supplier has a few more fields they can fill out. I plan on permissioning these extra fields by checking their role against spree_has_role?('supplier')
So what's the best way of adding the role to the database (do I add this to an initializer)?
How do I then add permissions to this role to be the same as the 'user' role?
At some point I'll want to extend the permissions, but one thing at a time.
I can't find any clear guide that shows how to do any of this (or at least anything that's been updated in the last year or two). I appreciate if any one can help me out with some instructions / examples.
P.s. I'm using Spree 2.2 Stable with Devise Auth.
Regular users have not any particular permission as you can see into the ability model (https://github.com/spree/spree/blob/master/core/app/models/spree/ability.rb) . You can just create the role in the database from the console using:
Spree::Role.create(name: 'Supplier')
If you need to be sure you have this role in the database and you want to put it into an initializer be sure to check if the role is not yet been created. You can use something like:
Spree::Role.find_or_create_by_name('Supplier')
At this point you can just use in the profile edit view something like:
<% if #user.has_spree_role?('Supplier') %>
...
additional fields here
...
<% end %>
I have 3 types of "users"
Shop
Provider
Customer
The last 2 users will have similar attributes such as
First Name
Last Name
and so on
And the Shop user type will have the most contrast between types.
As far as behaviours they will all be quite different, although Provider and Shop will inherent many of customer behaviours.
It seems the behaviours can be dealt with CanCan as I've researched.
I'm now attempting to how I should authenticate these types.
I have looked at the STI model but I couldn't grasp where I would these extra attributes.
My mental model is as follower:
User is a table and model
The types are abstract models that inherit from this.
So I'm wondering, how do I add attributes such as Business address for just the Shop type?
Or is it that the User Table has a column called Type and that type is associated with these type tables? And within the type tables are the extra attributes?
Don't even bother bringing Devise into this; Devise is for authentication not authorization. Authentication is determining whether or not someone who visits your site is who you think they are, like logging in. Authorization is deciding whether or not a user is allowed to perform some sort of action, like creating a new post.
What you want to do is have some sort of system that assigns a normal user your three different types; CanCan will do something like that. One way to do this on your own is using a permissions number based system. Let's say normal users have permissions level at 100, shop has a level at 50, and provider at 25. Using this system you can determine what actions a user can perform without having to make separate models, which will make your schema unnecessarily complicated. Here's an example of how this would work with say the UserController:
def show
if current_user.permissions == 100
render "customer_show"
elsif current_user.permissions == 50
render "shop_show"
else
render "provider_show"
end
end
The easiest way to do this is to add a column to the user's table called permissions that defaults to say 100 when a new row is created. Here's what that migration would look like:
def change
add_column :users, :permissions, :integer, default: 100
end
As for authenticating, don't worry about it. Let devise do it's thing; every user, no matter what type, will login and sign up in the same way, maybe just having separate forms for each that has a hidden field to set the permissions level for that specific kind of user.
I know I'm late to the party but I'm putting this out for future SO searchers. You CAN authorize actions with Devise. If you have devise models for 'buyer' & 'seller' you can add 'buyer_signed_in?' for whatever action you only want buyers to be able to do. You can also do more specific role-based authorizations as well - check out Devise' page
All in all, Tsiege's solution sounds pretty interesting. Let us know if you had any success with it!
I've got a typical Authlogic setup that I need to enhance to require Customer ID in addition to Login and Password.
I've read a bit about using a custom find method and another about using a global variable for accessing the additional parameter and a third referring to documentation about using scopes that doesn't seem to exist.
Seems like this should be easy, but I can't seem to find the right approach.
Anyone got a solution?
In your UserSession class, add:
find_by_login_method :find_by_customer_id_or_login
In your User class, create this customer finder:
def self.find_by_customer_id_or_login(login)
User.find_by_customer_id(login) || User.find_by_login(login)
end
This is assuming a User has both a customer_id field and a login field.
Add a customer_id column through a migration and validate_presence_of :customer_id on your model. It doesn't have anything to do with authlogic. Unless there is more that you are trying to do.
In my online store, users are allowed to change certain properties of their orders (e.g., their billing address), but not others (e.g., the origination ip address). Administrators, on the other hand, are allowed to modify all order properties.
Given, this, how can I use :attr_accessible to properly secure my Order model? Or will I have to use it to mark accessible all attributes that administrators can modify and refrain from using Order.update_attributes(params[:order]) in those controller actions that ordinary users can access?
Generally speaking, attr_accessible is not the tool you're looking for and Rails doesn't come with anything built in that does what you want.
If you want fine-grained control over who can update specific attributes in a model, you could do something like:
class Order < ActiveRecord::Base
def update_attributes_as_user(values, user)
values.each do |attribute, value|
# Update the attribute if the user is allowed to
#order.send("#{attribute}=", value) if user.can_modify?(attribute)
end
save
end
end
Then you can change your Order.update_attributes(params[:order]) to Order.update_attributes_as_user(params[:order], current_user) and assuming you implement the User#can_modify? method to return true in the correct cases, it should work.
I had the same problem and now I'm using this gem http://github.com/dmitry/attr_accessible_block
It's easy and used in some production website.
Yes, you'll have to modify the actions, so permissions are checked inside the actions. Calling Order#update_attributes will not work for the general user.
I can't rember a role-based authorization plugin that would allow something you are looking for. This is because these plugins mixin to the controllers and not the models. They would also need to mixin into ActiveRecord::Base to check for attr_accesible etc.