Code Monkey home page Code Monkey logo

milia's Introduction

Build Status Dependency Status

milia

Milia is a multi-tenanting gem for Ruby on Rails applications. Milia supports Devise.

You are viewing the documentation for using milia with Rails 5.x applications.
If you want to use Rails 4.2.x instead please switch to the Rails 4.x branch.

Intro

  • Milia is a solid choice for (SaaS) applications which are used by more than one tenant (i.e. companies or organizations) and is tailored for common use cases of multi-tenanted applications.
  • Milia allows to save the data of all tenants in the same database and enforces row based separation of the tenant data.
  • Milia uses the devise gem for user authentication and registration.

Milia highlights

  • Transparent to the main application code
  • Symbiotic with user authentication (supports devise out of the box)
  • Raises exceptions upon attempted illegal access
  • Enforces tenanting (not allow sloppy access to all tenant records)
  • Allows application flexibility upon new tenant sign-up, usage of eula information, etc
  • As non-invasive (as possible) to Rails code
  • Uses row-based tenanting (for good reasons)
  • Uses default_scope to enforce tenanting
  • See Milia in action in the Sample App

Basic concepts

Tenants == Organizations with Users / Members

A tenant is an organization with many members (users). Initially a user creates a new organization (tenant) and becomes its first member (and usually admin). Then he invites further members who can then login and join the tenant. Milia ensures that users can only access data of their own tenant (organization).

Tenanted models

Models which belong to a certain tenant (organization).
Add acts_as_tenant to the model body to activate tenanting for this model.
Most of your tables (except for pure join tables, users, and tenants) should be tenanted. Every record of a tenanted table needs to have a tenant_id set. Milia takes care of this.

Universal models

Models which aren't specific to a tenant (organization) but have system wide relevance. Add acts_as_universal to the model body to mark them as universal models.
Universal tables never contain critical user/company information. The devise user table must be universal and should only contain email, encrypted password, and devise-required data. All other user data (name, phone, address, etc) should be broken out into a tenanted table called members (Member belongs_to :user, User has_one :member). The same applies for organization (account or company) information. A record of a universal table must have tenant_id set to nil. Milia takes care of this.

Join tables

Pure join tables (has_and_belongs_to_many HABTM associations) are neither Universal nor Tenanted.

Tutorials + Documentation

  • Up to date starting point is the README you're currently viewing.
  • For more details on token authentication, exceptions, callbacks, devise setup etc. have a look at the additional README_DETAILS.
  • Tutorial: There's a good Milia tutorial at myrailscraft.
  • Check out the general three-part blog post about Multi-tenanting Ruby on Rails Applications on Heroku.

Sample app

You can get a sample app up and running yourself using an easy, interactive RailsApp generator and an according Milia generator. If desired the generator can also prepare everything for you to push your app to Heroku. The sample app uses devise with the invite_member capability (and optionally recaptcha for new account sign-ups). It creates skeleton user, tenant and member models.

Simply follow the following steps:

mkdir milia-sample-app
cd milia-sample-app
rvm use ruby-2.3.1@milia-sample-app --ruby-version --create
gem install rails
rails new . -m https://raw.github.com/RailsApps/rails-composer/master/composer.rb

An interactive setup starts which asks you some questions.

  • Choose "Build a RailsApps example application"
  • Choose "rails-devise" as the example template
  • Choose Template engine "HAML"
  • Choose "Devise with default modules"
  • Choose the other options depending on your needs

After the setup finished add to your Gemfile:
gem 'milia'

Install milia: bundle install

In app/controllers/application_controller.rb add the following line immediately after protect_from_forgery:
before_action :authenticate_tenant!

Run the following commands:

spring stop
rails g milia:install --org_email='[email protected]' --skip_devise_generators=true
  • Remove lower line "before_action :authenticate_tenant!" which has been added to app/controllers/application_controller.rb by the milia generator.
  • Remove the lines @extend .text-xs-center; (if any) from the file 1st_load_framework.css.scss.
  • Remove the file app/views/devise/registrations/new.html.erb

Setup the database: rake db:drop db:create db:migrate

Start the server: rails server

Open http://127.0.0.1:3000/users/sign_up in your browser. You're ready to go!

Previous sample app

For your reference: An outdated milia+devise sample app can be found at https://github.com/dsaronin/sample-milia-app and is live on Heroku: http://sample-milia.herokuapp.com
The according instructions on how to generate this sample app can be found at doc/sample.sh.

There are also outdated step-by-step instructions for setting this sample app up manually at doc/manual_sample.sh.

  • Step 1: Sample with simple devise only
  • Step 2: Add milia for complete tenanting
  • Step 3: Add invite_member capability

Installation

Adding milia to a new application

The quickest way: Follow the simple instructions of the chapter Sample App to generate a new app which uses devise+milia.

Add milia to an existing application

The recommended way to add multi-tenanting with milia to an existing app is to bring up the Sample App, get it working and then graft your app onto it. This ensures that the Rails+Devise setup works correctly.

Go step by Step

Don't try to change everything at once! Don't be a perfectionist and try to bring up a fully written app at once!

Just follow the instructions for creating the sample, exactly, step-by-step. Get the basics working. Then change, adapt, and spice to taste.

Bare minimal manual setup

(If you generated a [Sample App](Sample App) all of the following steps have been done already.)

Add to your Gemfile:

  gem 'milia', '~>1.3'

Then run the milia generator:

  $ bundle install
  $ rails g milia:install --org_email='<your smtp email for dev work>'

Note: The milia generator has an option to specify an email address to be used for sending emails for confirmation and account activation.

For an in depth explanation of what the generator does have a look at README_DETAILS.

Make any changes required to the generated migrations, then:

  $ rake db:create
  $ rake db:migrate

Application controller

app/controllers/application_controller.rb add the following line IMMEDIATELY AFTER line 4 protect_from_forgery

  before_action :authenticate_tenant!   # authenticate user and sets up tenant

  rescue_from ::Milia::Control::MaxTenantExceeded,   :with => :max_tenants
  rescue_from ::Milia::Control::InvalidTenantAccess, :with => :invalid_tenant

Setup base models

  • Necessary models: User, Tenant
  • Necessary migrations: user, tenant, tenants_users (join table)

Generate the tenant migration

  $ rails g model tenant tenant:references name:string:index

Generate the tenants_users join table migration

  $ rails g migration CreateTenantsUsersJoinTable tenants users

EDIT: db/migrate/20131119092046_create_tenants_users_join_table.rb then uncomment the first index line as follows: t.index [:tenant_id, :user_id]

ALL models require a tenanting field, whether they are to be universal or to be tenanted. So make sure you have migrations for all models which add the following:

db/migrate/xxxxxxx_create_model_xyz.rb

  t.references :tenant

Tenanted models also require indexes for the tenant field.

  add_index :<tablename>, :tenant_id

BUT: Do not add any belongs_to :tenant statements into any of your models. milia will do that for all. However it makes sense to add into your app/models/tenant.rb file one line per tenanted model such as the following (replacing with your model's name):

  has_many  :<model>s, dependent: :destroy

The reason for this is that if you wish to have a master destroy tenant action, it will also remove all related tenanted tables and records automatically.

Do NOT add a reference to the user model such as

  has_many  :users, dependent: :destroy

because it produces errors.

Designate which model determines the account

Add the following acts_as_... to designate which model will be used as the key into tenants_users to find the tenant for a given user. Only designate one model in this manner e.g.:

app/models/user.rb

  class User < ActiveRecord::Base

    acts_as_universal_and_determines_account

  end
Designate which model determines the tenant

Add acts_as_universal_and_determines_tenant to designate which model will be used as the tenant model. It is this id field which designates the tenant for an entire group of users which exist within a single tenanted domain. Only designate one model in this manner.

app/models/tenant.rb

  class Tenant < ActiveRecord::Base
    
    acts_as_universal_and_determines_tenant
    
  end 
Clean up tenant references

Clean up any generated belongs_to tenant references in all models which the generator might have generated (both acts_as_tenant and acts_as_universal).

Setup your custom models

Designate tenanted models

Add acts_as_tenant to ALL models which are to be tenanted. Example for a Post model:

app/models/post.rb

  class Post < ActiveRecord::Base
    
    acts_as_tenant
  
  end
Designate universal models

Add acts_as_universal to ALL models which are to be universal.

Role based authorization

You can use any role based authorization you like, e.g. the rolify gem with cancancan, authority or pundit.

Milia API Reference Manual

Get current tenant

From models call Tenant.current_tenant or Tenant.current_tenant_id to get the current tenant.

Change current tenant

Call set_current_tenant( tenant_id ) from controllers. (for example, if a member can belong to multiple tenants and wants to switch between them). NOTE: you will normally NEVER do this manually at the beginning of a session. Milia does this automatically during authorize_tenant!.

From background job, migration, rake task or console you can use Tenant.set_current_tenant(tenant). tenant can either be a tenant object or an integer tenant_id; anything else will raise an exception.

Use with caution! Normally tenants should never be changed from within models. It is only useful and safe when performed at the start of a background job (DelayedJob#perform), rake task, migration or start of rails console.

Iterate over tenants

To iterate over all instances of a certain model for all tenants do the following:

Tenant.find_each do |tenant|
  Tenant.set_current_tenant(tenant)
  Animal.update_all alive: true
end

Rails Console

Note that even when running the console, (rails console) it will be run in multi-tenanting mode. Call Tenant.set_current_tenant(tenant_id) accordingly.

Milia callbacks

In some applications, you will want to set up commonly used variables used throughout your application, after a user and a tenant have been established and authenticated. This is optional and if the callback is missing, nothing will happen.

app/controllers/application_controller.rb

  def callback_authenticate_tenant
    # set_environment or whatever else you need for each valid session
  end

Security / Caution

  • Milia designates a default_scope for all models (both universal and tenanted). Rails merges default_scopes if you use multiple default_scope declarations in your model, see ActiveRecord Docs. However by unscoping via unscoped you can accidentally remove tenant scoping from records. Therefore we strongly recommend to NOT USE default_scope at all.
  • Milia uses Thread.current[:tenant_id] to hold the current tenant for the existing Action request in the application.
  • SQL statements executed outside the context of ActiveRecord pose a potential danger; the current milia implementation does not extend to the DB connection level and so cannot enforce tenanting at this point.
  • The tenant_id of a universal model will always be forced to nil.
  • The tenant_id of a tenanted model will be set to the current_tenant of the current_user upon creation.
  • HABTM (has_and_belongs_to_many) associations don't have models; they shouldn't have id fields (setup as below) nor any field other than the joined references; they don't have a tenant_id field; rails will invoke the default_scope of the appropriate joined table which does have a tenant_id field.
  • Your code should never try to change or set the tenant_id of a record manually.
    • milia will not allow it
    • milia will check for deviance
    • milia will raise exceptions if it's wrong and
    • milia will override it to maintain integrity.
  • You use milia solely at your own risk!
    • When working with multi-tenanted applications you handle lots of data of several organizations/companies which means a special responsibility for protecting the data as well. Do in-depth security tests prior to publishing your application.

Contributing to milia

  • Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
  • Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
  • Fork the project
  • Start a feature/bugfix branch
  • Commit and push until you are happy with your contribution
  • Make sure to add tests for it. This is important so we don't break the feature in a future version unintentionally.
  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so we can cherry-pick around it.

Testing milia

For instructions on how to run and write tests for milia please consider the README for testing

Changelog

See CHANGELOG.md for changes and upgrade instructions.

License

See LICENSE.txt for further details.

milia's People

Contributors

anka avatar creativetags avatar dsaronin avatar jekuno avatar krolow avatar philipkobernik avatar russelltsherman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

milia's Issues

Doing a global admin panel

This is not so much an issue as a plea for guidance! We have a nicely working multi-tenanted site, but, how can we write back-end admin tools that let us see data across all tenants? Something like rails_admin.
Has anyone done this or can point to what to do?
Maybe adding a user to all tenants?

Tips appreciated!

Wrong tenant access at sign_up

I encountered a problem adding milia-1.2.0 to my rails-4.2.0 application (I unfortunately couldn't graft my app onto the sample-milia-app because the existing application is too evolved).

I setup everything as described in your documentation. When calling http://localhost:3000/users/sign_up the form for signing up a new tenant shows up as expected. However after submitting the form an error flash message wrong tenant access; sign out & try again appears.

I debugged the problem and found out the following:
The data get processed by Milia::RegistrationsController as expected. The controller

  • creates the tenant correctly, then
  • enters devise_create( user_params ) in line 36, then
  • tries to save the devise user with resource.save in line 122, then
  • raises exception in milia/base.rb, line 62: raise ::Milia::Control::InvalidTenantAccess unless obj.tenant_id.nil?
  • gets caught by application_controller writing the flash error wrong tenant access; sign out & try again

As far as I understand the problem is that the user object in the callback in base.rb has a tenant_id even though it is an universal object. I didn't find out how to solve this problem. Any help would be greatly appreciated! :)

Some information which might help to narrow down the problem:

  • I work on a brand new database.
  • I use Postgres, milia-1.2.0, devise-3.4.1 and rails-4.2.0
  • My user model contains the line acts_as_universal_and_determines_account.
  • I use the following devise modules: :invitable, :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable

The log looks as follows:

Started POST "/users" for ::1 at 2015-03-13 15:32:44 +0100
Processing by Milia::RegistrationsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"xxxxx", "user"=>{"name"=>"Admin TestCompany", "email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "tenant"=>{"name"=>"TestCompany"}, "commit"=>"Register"}
   (0.2ms)  BEGIN
  SQL (1.1ms)  INSERT INTO "tenants" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["name", "TestCompany"], ["created_at", "2015-03-13 14:32:45.045574"], ["updated_at", "2015-03-13 14:32:45.045574"]]
MILIA >>>>> [change tenant] new: 1  old: %
  User Exists (1.6ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
  User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE (users.tenant_id IS NULL) AND "users"."confirmation_token" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["confirmation_token", "72a251b1aa2a2ac60e4f7025370d259e75338aab60540e41dfca6420769ffe46"]]
  SQL (0.9ms)  INSERT INTO "users" ("email", "encrypted_password", "name", "role", "skip_confirm_change_password", "created_at", "updated_at", "confirmation_token", "confirmation_sent_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"  [["email", "[email protected]"], ["encrypted_password", "$2a$10$aPLmuYCDLh23Z74jErof8OEvbw7BnEJXa0tOgjUkyStx9ECxuJH0q"], ["name", "Admin TestCompany"], ["role", 0], ["skip_confirm_change_password", "t"], ["created_at", "2015-03-13 14:32:45.135246"], ["updated_at", "2015-03-13 14:32:45.135246"], ["confirmation_token", "72a251b1aa2a2ac60e4f7025370d259e75338aab60540e41dfca6420769ffe46"], ["confirmation_sent_at", "2015-03-13 14:32:45.360023"]]
  Tenant Load (0.4ms)  SELECT  "tenants".* FROM "tenants" WHERE (tenants.tenant_id IS NULL) AND "tenants"."id" = $1 LIMIT 1  [["id", 1]]
  User Exists (0.4ms)  SELECT "users".* FROM "users" WHERE (users.tenant_id IS NULL) AND "users"."tenant_id" = $1 AND "users"."id" = $2  [["tenant_id", 1], ["id", 1]]
  User Exists (0.5ms)  SELECT  1 AS one FROM "users" WHERE ("users"."email" = '[email protected]' AND "users"."id" != 1) LIMIT 1
   (0.2ms)  ROLLBACK
Redirected to http://localhost:3000/users/sign_up
  • The newly created tenant gets set in the session.
  • The attributes of the user resource (which cannot be saved) don't contain a tenant_id before calling resource.save:
"{"id"=>nil, "email"=>"[email protected]", "encrypted_password"=>"$2a$10$aPLmuYCDLh23Z74jErof8OEvbw7BnEJXa0tOgjUkyStx9ECxuJH0q", "reset_password_token"=>nil, "reset_password_sent_at"=>nil, "remember_created_at"=>nil, "sign_in_count"=>0, "current_sign_in_at"=>nil, "last_sign_in_at"=>nil, "current_sign_in_ip"=>nil, "last_sign_in_ip"=>nil, "created_at"=>nil, "updated_at"=>nil, "name"=>"firmenadmin", "confirmation_token"=>nil, "confirmed_at"=>nil, "confirmation_sent_at"=>nil, "unconfirmed_email"=>nil, "role"=>0, "invitation_token"=>nil, "invitation_created_at"=>nil, "invitation_sent_at"=>nil, "invitation_accepted_at"=>nil, "invitation_limit"=>nil, "invited_by_id"=>nil, "invited_by_type"=>nil, "invitations_count"=>0, "skip_confirm_change_password"=>true, "tenant_id"=>nil}"

Stuck getting it setup

I've followed the readme and tried running the test app but I'm stuck. Shouldn't it start by registering a new tenant?

Model validation

I recently ran into an issue where I wasn't sure if my validations against a tenanted model was working correctly.

When I was using the following code:

validates_uniqueness_of :name

The model would not save a record with a name that had an identical name to another record which was under a different tenant. So for example if I had a record were name = joe and tenant_id = 1. Then I went in under tenant #2 and tried to save another record with name = joe, it would not save and say the name had to be unique. I ended up using the following validation to fix it.

validates_uniqueness_of :name, :scope => :tenant_id

My question is just is this the correct way to handle unique validation with milia, or did I bork something in my application and shouldn't need the :scope => :tenant_id part? If I did screw something up, do you have any pointers on where to start looking?

FYI, everything else "seems" to operate as expected. Here is the first part of my model code just for your info.

class Plan < ActiveRecord::Base
  #sets up model as a tenant in milia
  acts_as_tenant

  has_many :donations
        attr_accessible :stripe_plan_id, :name, :summary, :title, :amount

  validates :amount, presence: true
  validates_uniqueness_of :name, :scope => :tenant_id, :case_sensitive => false
  validates :name, presence: true
  validates :stripe_plan_id, presence: true, uniqueness: { case_sensitive: false }
  validates :summary, presence: true
  validates_uniqueness_of :summary, :scope => :tenant_id, :case_sensitive => false

Second FYI, I was installing the AASM gem at the time too (though I did uninstall AASM to make sure it wasn't causing the issue). I saw you had AASM experience too and just wondered if you had seen any conflicts between AASM and Milia.

Thanks, any of your thoughts will be appreciated.

acts_as_universal_and_determines_tenant does not "unset" the default_scope.

Hi,

I'm trying to set it up. I told the Tenant model to be universal but the generated SQL shows up that it is looking for a tenant_id on the Tenant model:

Mysql2::Error: Unknown column 'tenants.tenant_id' in 'where clause': SELECT  `tenants`.* FROM `tenants`  WHERE `tenants`.`code` IS NULL AND (tenants.tenant_id IS NULL) LIMIT 1

app/models/tenant.rb

class Tenant < ActiveRecord::Base
  acts_as_universal_and_determines_tenant

  def self.default
    Tenant.find_by_code 'foo'
  end
end

I don't know if it is related, but I don't want a user-based tenant system but a subdomain-based one. So I skip what I think was not related from the README.

Redirect loop

Hey

I'm experiencing a redirect loop (even with your sample app on http://sample-milia.herokuapp.com) when following these steps:

  1. sign up
  2. confirm account and login
  3. sign out
  4. try to register with the same email (it obviously fails)
  5. login

Then, the redirect loop occurs because of the Milia::Control::InvalidTenantAccess- I guess the tenant_id stays in the Thread and that causes the invalid_tenant error which causes redirects from index to user's landing page and back.

screen shot 2014-09-10 at 11 56 19

I suspect we would have to clear Thread.current[:tenant_id]somewhere along the way?

Member is able to invite a new member

We have integrated milia in our App and while testing the member invitation, we found the member is also allowed to invite new members.

Do we need to restrict this from our application or can this be handled in your gem itself.

Integration with devise_invitatable gem

When I tried to send invitation to a new user, I don't know how to pass the tenant_id to the new user.
User acts as universal, so its tenant_id would have to be set to nil.

But when a user tried to validate its invitation_token, rails could not find a user with the token and tenant_id => nil.

I think the problem might lie in the tenant_user table, could you tell me your suggestion?

include invite_member API into milia

include within milia all the devise work-arounds for simply inviting a member into the organization. Needs to skip requiring initial password to create the user, but should require the newly confirming member to create a password.
This will be enabled by the setup config.use_invite_member = true option. When false, will fall-back to typical devise handling.

ParameterMissing: tenant

I'm trying to setup milia for the very first time and I got an error after submiting sign-up form:

ActionController::ParameterMissing in Milia::RegistrationsController#create
param not found: tenant

stack trace showed me the place and I check it with binding.pry as well:
milia (1.0.0) app/controllers/registrations_controller.rb:82:in `sign_up_params_tenant':

  def sign_up_params_tenant()
    params.require(:tenant).permit( ::Milia.whitelist_tenant_params ) # <- line 82
  end

I asked for help at stackoverflow as well. I would appreciate your advice.

What is the thinking behind using Thread to store current tenant

This isn't really an issue but I curious to know why you have chosen to store the current tenant in the Thread.

Is this not the equivalent to a global variable?
Am I expect to maintain my own current tenant id in either the session or the user object and move it into the Thread variable at the beginning of each request?

Sign up not working

I've downloaded the sample-milia-app and it is up and running on my local server (meaning I can see the root page page and I can get to the sign up view).

A problem that I am having is that I am just trying to sign up my first organization through the form. When I submit the form, the form just sits there. My logs say this is happening:

Started POST "/users" for 127.0.0.1 at 2014-01-08 01:18:39 +0000
Started POST "/users" for 127.0.0.1 at 2014-01-08 01:18:39 +0000
Processing by Milia::RegistrationsController#create as HTML
Processing by Milia::RegistrationsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"Sy2yLxZ7Sjpmc0laQWspuwan9wQcb83l7Hs0BjcpNXo=", "user"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "tenant"=>{"name"=>""}, "coupon"=>{"coupon"=>""}}
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"Sy2yLxZ7Sjpmc0laQWspuwan9wQcb83l7Hs0BjcpNXo=", "user"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "tenant"=>{"name"=>""}, "coupon"=>{"coupon"=>""}}
   (81.7ms)  BEGIN
   (81.7ms)  BEGIN
  SQL (254.1ms)  INSERT INTO "tenants" ("created_at", "name", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", Tue, 07 Jan 2014 17:18:39 PST -08:00], ["name", ""], ["updated_at", Tue, 07 Jan 2014 17:18:39 PST -08:00]]
  SQL (254.1ms)  INSERT INTO "tenants" ("created_at", "name", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", Tue, 07 Jan 2014 17:18:39 PST -08:00], ["name", ""], ["updated_at", Tue, 07 Jan 2014 17:18:39 PST -08:00]]
  User Exists (83.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
  User Exists (83.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
  Rendered /home/action/.rvm/gems/ruby-2.0.0-p353@milia/gems/devise-3.2.2/app/views/devise/shared/_links.erb (0.4ms)
  Rendered /home/action/.rvm/gems/ruby-2.0.0-p353@milia/gems/devise-3.2.2/app/views/devise/shared/_links.erb (0.4ms)
  Rendered devise/registrations/new.html.haml within layouts/sign (5.8ms)
  Rendered devise/registrations/new.html.haml within layouts/sign (5.8ms)
   (82.9ms)  ROLLBACK
   (82.9ms)  ROLLBACK
Completed 200 OK in 901ms (Views: 11.6ms | ActiveRecord: 831.1ms)
Completed 200 OK in 901ms (Views: 11.6ms | ActiveRecord: 831.1ms)

Devise doesn't seem to like something about the form, but it doesn't give me any errors or anything. Any clues as to what is missing? I am using beta 3.

Thanks.

wrong number of arguments (2 for 1)

I am getting this error when registering a new user, and self.create_new_tenant is called.

this is my form:

<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :class => "form" }) do |f| %>

    <%= f.input :email, label: false, placeholder: "email", :class => "text_field" %>
    <br>

    <%= f.input :password, label: false, placeholder: "password", :class => "text_field" %><br>

    <%= f.input :password_confirmation, label: false, placeholder: "confirm password", :class => "text_field" %>
    <br>

    <%= simple_fields_for( :tenant ) do |w| %>
      <%= w.input :name, label: false, placeholder: "Organization account", :class => "text_field" %>
    <% end %><br>


    <%= f.button :submit, 'create account', class: "btn btn-primary" %>
  </div>

<% end %>

and the parameters being sent:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"WnT5KNuhV1E7UBvVY4zQ7BPA2KAkIjNr8ofyLx6fNrM=", "user"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "tenant"=>{"name"=>"company_name"}, "commit"=>"create account"}

save_and_invite_member() doesn't send an email

Everything seems to work otherwise, but no email send is attempted in the logs.

Running in development mode my config/environments/development.rb has:

config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp

ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => "587",
:authentication => :plain,
:user_name => ENV["SMTP_EMAIL"],
:password => ENV["SMTP_PASSWORD"],
:enable_starttls_auto => true
}

Default Scopes

Is it right to say that "Rails 3.2 onwards, the last designated default scope overrides any prior scopes and will invalidate multi-tenanting"? Rails docs says "If you use multiple default_scope declarations in your model then they will be merged together". I tested it myself:

class Article < ActiveRecord::Base
  acts_as_tenant
  default_scope {
    where("created_at > '2015-01-01'")
  }
end

Console:

Tenant.set_current_tenant(1)
Article.all
SELECT "articles".* FROM "articles" WHERE (articles.tenant_id = 1) AND (created_at > '2015-01-01')

Member data for superuser

I have a superuser which belongs to several tenants. Data such as first_name and last_name are kept in a separate members table as recommended. I understand your explanations in https://github.com/dsaronin/milia#inviting-additional-usermembers as follows:

  • I need one user record for this superuser
  • I need entries in tenants_users to define the membership of this user to the according tenants
  • And: I need one member record for this user for each tenant this user can access (this is because the members table is tenanted; only the users table isn't tenanted)

However:

  1. your docs say there needs to be a has_one :member relation on the user (and not a has_many).
  2. It doesn't feel clean to replicate the members data (such as first_name and last_name) n times if the user belongs to n companies.

What is the recommended way to do it with milia?

New Member Signup Question

Thanks for your work on this! I am using it for a couple of projects now.

When I add a new member for a tenant, a password is being generated and used for the user creation for devise. The email goes out with a confirmation link. When they click on the link, it automatically logs them in and puts them on the welcome screen.

I also see this in the code and of particular interest is the change_or_confirm_user and line 38: if ( @confirmable.skip_confirm_change_password || @confirmable.valid? )

In the situation I described, I would have thought this would have returned false and thus would hit the else statement on line 40. However it appears to be resulting in true and executing the do_confirm (which logs them in automatically). Yet my new member never gets to set up their own password via a show view that I build and your update method.

I may not be following the code correct but any guidance would be appreciated.

Milia issue with seed_fu

Hi there,

I'm really looking forward to the new milia gem with rails 4 and devise 3 support!

I was testing out the beta3 and ran into an issue, I am using the seed_fu gem to populate default tenant data in the following manner, which was working with Milia 0.3.30

e.g. in a single file

Tenant.set_current_tenant Tenant.where(:name => 'First').first

Domain.seed_once(:uri,
    {:uri => 'testing1.com'},
    {:uri => 'testing2.com'}
)

Tenant.set_current_tenant Tenant.where(:name => 'Second').first

Domain.seed_once(:uri,
    {:uri => 'testing3.com', :primary => true}
)

Now it throws an
Milia::Control::InvalidTenantAccess (Domain.rb uses acts_as_tenant)

I get the same behaviour when trying this via the rails console, even though Tenant.current_tenant shows the correct one is selected, it fails exactly on base.rb:31 since the tenant_id check fails.

I went through the seed_fu src to see what it was doing,
It does a Record.new followed by assign_attributes then save which when run in that sequence in the console works just fine. confused :?

Sample app: failed auth user

I checked out your sample application. Registering and signing in as a user works fine.
However opening the profile page (the page to edit the signed in user) at http://localhost:3000/users/edit produces an error in the sample app:
Logfile: MILIA >>>>> [failed auth user]
Flash error: cannot sign in as <email missing>; check email/password

This error already occurs on opening the page (without posting the form). In my own app I get the same error as in the sample app.

Do you have any ideas on how to fix this?

Add management GUI

Hi,
I'm trying to create an administration page where I can see all of the users using my app.
I have created a controller with privileges only for me, and I have a regular index view.
In this controller I can access the users by using '@users = User.all' but when I try to get to the tenant (to show it's ID and name), I can't do that. Any suggestions how can I access all the tenants from this admin controller?

Thanks!

Issue with Strong Parameters and prep_signup_view

Hi Daudi - many thanks for all of the work you have put into your milia gem! I have been trying to integrate 1.0.0-beta3 into my own project and hit an awkward issue that had me scratching my head for a couple of days and I think has highlighted an issue in the milia registrations controller and prep_signup_view code.

I was getting an ActiveModel::ForbiddenAttributesError error on my sign up form if hit submit whilst leaving the "Organisation Name" field blank (leaving the user fields blank was fine). When I ran your sample application I noticed that you don't have this issue (although your coupon field value becomes a hash for some reason - i'm leaving the coupon out so ignored this).

To cut a long painful story short, I had added a validation to my tenant model for the 'name' field: -

class Tenant < ActiveRecord::Base
    validates :name, presence: true, length: { maximum: 80 }, uniqueness: { case_sensitive: false }

I think it reasonable to want to add some validation on the tenant to ensure uniqueness, presence and length etc. This leads to a problem in the milia registrations controller. If the tenant does not save properly then the form is re-displayed by your registration controller: -

Tenant.transaction  do 
      @tenant = Tenant.create_new_tenant(sign_up_params_tenant, sign_up_params_coupon)
      if @tenant.errors.empty?   # tenant created

        initiate_tenant( @tenant )    # first time stuff for new tenant

        devise_create   # devise resource(user) creation; sets resource

        if resource.errors.empty?   #  SUCCESS!

            # do any needed tenant initial setup
          Tenant.tenant_signup(resource, @tenant, params[:coupon])

        else  # user creation failed; force tenant rollback
          raise ActiveRecord::Rollback   # force the tenant transaction to be rolled back  
        end  # if..then..else for valid user creation

      else
        prep_signup_view( @tenant, params[:user] , params[:coupon]) # PROBLEM
        render :new
      end # if .. then .. else no tenant errors

By adding a validation on the tenant I caused the tenant save to fail we get sent through prep_signup_view before the form is re-rendered. You are passing the tenant object instance variable but passing the params[:user] hash. The params hash does not have any strong parameter whitelisting (permits etc.) on it and so causes the ForbiddenAttributesError when klass_option_obj calls 'new' on User using this hash.

Further down the controller you call prep_signup_view like this: -

prep_signup_view( sign_up_params_tenant, sign_up_params, sign_up_params_coupon )

This is great because it preps the form by using the permitted strong parameter versions of the parameters but has the downside that all error messages are lost. The errors are lost because prep_signup_view recreates the @user, @Tenant and @coupon instance variables as new from the params hashes.

I have tested this modification to the registration create method which fixes the strong parameter issue and makes sure that ALL validation errors are available to the form: -

def create

  sign_out_session!
  build_resource(sign_up_params) # added by dave
  prep_signup_view( sign_up_params_tenant, sign_up_params, sign_up_params_coupon ) # added by dave

     # validate recaptcha first unless not enabled
  if !::Milia.use_recaptcha  ||  verify_recaptcha

    Tenant.transaction  do 
      @tenant = Tenant.create_new_tenant(sign_up_params_tenant, sign_up_params_coupon)
      if @tenant.errors.empty?   # tenant created

        initiate_tenant( @tenant )    # first time stuff for new tenant

        devise_create   # devise resource(user) creation; sets resource

        if resource.errors.empty?   #  SUCCESS!

            # do any needed tenant initial setup
          Tenant.tenant_signup(resource, @tenant, params[:coupon])

        else  # user creation failed; force tenant rollback
          raise ActiveRecord::Rollback   # force the tenant transaction to be rolled back  
        end  # if..then..else for valid user creation

      else
    resource.valid?
        #prep_signup_view( @tenant, resource, sign_up_params_coupon ) # removed by dave
        render :new
      end # if .. then .. else no tenant errors

    end  #  wrap tenant/user creation in a transaction

  else
    flash[:error] = "Recaptcha codes didn't match; please try again"
    resource.valid?
    @tenant.valid?
    #prep_signup_view( @tenant, resource, sign_up_params_coupon ) # removed by dave
    render :new
  end

end   # def create

By placing prep_signup_view at the top - it makes sure that all of the instance variables are created unless they already exist.

I needed to call devises build_resource function and the calls to valid? so that all form objects get validated, even if there are recaptcha errors or tenant problems. The form in your sample app doesn't appear to display any error messages.

One last change, it would be good to remember the tenant name even if there are errors with the user object validations, e.g. password_confirmation does not match. Instead of creating a new tenant form entry each time, you could use the existing one if already defined: -

      .group
        = fields_for( :tenant, @tenant || Tenant.new ) do |w|
          = w.label( :name, 'Organization', :class => "label" ) 
          = w.text_field( :name, :class => "text_field")
          %span.description unique name for your group or organization for the new account

This is a little ugly so it might be better to just use fields_for( @Tenant ) and add your prep_signup_view function to the devise controllers #new method (otherwise @Tenant will by nil the first time the form is called).

Thanks for having a look through my issue - I hope you will consider some of my suggestions! I do think that, as it stands, the sign_up form is broken if the tenant does not save properly (if someone innocently adds some simple validations to it!). I'm sure that a lot of people will be basing new applications on your sample application, so it would be very helpful if it it's able to display validation errors and remember the tenant and coupon fields successfully.

regards

Dave

Making application-wide changes to tenanted models

Is there a way, say, from a rake task, to make changes to all instances of a tenanted model?

From my reading of the docs it seems that I might have to loop over all the tenants, set each one as the current tenant, and operate on each of their associated tenanted models.

Is there a better way?

Api with authentication_token

My webApp has api functions. get method with authentication_token after sign_in user app redirected to root_path. Is there any way to perform controller action with parameters that I need without redirection?

Started GET "/api/bonus_cards/balance?auth_token=v5E-eYKb27yZCOOOOOJJOOJJ&number=00001" for 127.0.0.1 at 2015-03-30 15:46:59 +0300
Processing by ApiController#balance as HTML
Parameters: {"auth_token"=>"v5E-eYKb27yZCOOOOOJJOOJJ", "number"=>"00001"}
User Load (4.1ms) SELECT "users".* FROM "users" WHERE (users.tenant_id IS NULL) AND "users"."auth_token" = 'v5E-eYKb27yZCOOOOOJJOOJJ' LIMIT 1
(0.3ms) BEGIN
SQL (0.6ms) UPDATE "users" SET "current_sign_in_at" = $1, "last_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = 12 ["current_sign_in_at", "2015-03-30 15:46:59.962394"], ["last_sign_in_at", "2015-03-30 15:46:59.103771"], ["sign_in_count", 49], ["updated_at", "2015-03-30 15:46:59.964500"] COMMIT
Tenant Load (15.0ms) SELECT "tenants".* FROM "tenants" INNER JOIN "tenants_users" ON "tenants"."id" = "tenants_users"."tenant_id" WHERE (tenants.tenant_id IS NULL) AND "tenants_users"."user_id" = $1 ORDER BY "tenants"."id" ASC LIMIT 1 [["user_id", 12]]
MILIA >>>>> [change tenant] new: 11 old: %
Tenant Load (0.4ms) SELECT "tenants".* FROM "tenants" INNER JOIN "tenants_users" ON "tenants"."id" = "tenants_users"."tenant_id" WHERE (tenants.tenant_id IS NULL) AND "tenants_users"."user_id" = $1 [["user_id", 12]]
Redirected to
Redirected to http://localhost:3000/
Completed 302 Found in 43ms (ActiveRecord: 20.9ms)

Started GET "/" for 127.0.0.1 at 2015-03-30 15:47:00 +0300
Processing by RestaurantsController#index as HTML
Completed 401 Unauthorized in 1ms

#application controller
def auth_by_token!
    # special case for designated actions only
  if ( user = User.find_by_auth_token( params[:auth_token] ) )

      # create a special session after authorizing a user
    reset_session
    sign_in(user, store: false)  # devise's way to signin the user
    # now continue with tenant authorization & set up
    true  # ok to continue  processing

  else
    act_path = controller_name.to_s + '/' + action_name.to_s
    logger.info("SECURITY - access denied #{Time.now.to_s(:db)} - auth: #{params[:userfeed] }\tuid:#{(user.nil? ? 'n/f' : user.id.to_s)}\tRequest: " + act_path)
    render( :nothing => true, :status => :forbidden) #  redirect_back   # go back to where you were
    nil   # abort further processing
  end

end

and in ApiController I have

#ApiController
skip_before_action :authenticate_tenant!
prepend_before_action :auth_by_token!, only: [:balance]
protect_from_forgery

Milia and dashing-rails (engine) integration

I'm trying to sort out how to integrate dashing-rails, which provides a Rails engine of Shopify's Dashing dashboard framework, into a Milia-enabled app.

https://github.com/gottfrois/dashing-rails

In general, what should be required to use an engine with Milia? Setting the current tenant seems like an obvious requirement but I'm unsure of how or where to do that when using an engine. Any tips?

Upgrade from 0.0.3 to 1.0.0

Hi, dsaronin. Sorry I am late for your updates. I am using 0.0.3 version milia in my app and I love it, although sometimes it breaks when it is facing devise_invitable and devise. After I came to know that you have updated it, I was quite happy and found that you have did a fantastic work again.

I could not find time to build a new app to test for you, but I would like to use the new version (currently 1.0.0-beta3) in my existing app which means, I have to know exactly what would be different between the old and the new, especially the database part.

Thanks.

Recapcha & ENV Locations

Hello,

I couldn't seem to find where the option to disable Recapcha was.
Also, I didn't find the location of the ENV variables in the documenation. I assumed maybe an application.yml?

Any help appreciated.

web-app-theme

Hi Daudi, I cannot get "bundle install" to work as web-app-theme fails with rails 4.1.1 "Bundler could not find compatible versions for gem "rails":
In Gemfile:
web-app-theme (>= 0) ruby depends on
rails (~> 4.0.1) ruby
rails (4.1.1)
Any thoughts would be appreciated. My git repo is stuartn60/sample-milia-app.
Thanks, Stuart

Delete a tenant

Hi,
When I delete tenant, the user, member and all it's records is still in the DB.
I have added to tenants.rb model:
has_many :members, dependent: :destroy
has_many :all_other_models_acts_as_tenants, dependent: :destroy

I'm working with postgresql.
I deleted the tenant from rails console and also directly from the pg-Admin gui.
also tried to delete the member, the user etc.

So my question is what is the way to delete Tenant with all it's associated records?

Thanks!

milia:install error

OS: Ubuntu 12.04 (running in Vagrant)
RVM in use

rails g milia:install --org_email='[email protected]'
/home/vagrant/code/sample-milia-app/config/environments/development.rb:1:in <top (required)>': undefined methodconfigure' for #SampleMiliaApp::Application:0xac0ce5c (NoMethodError)
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:229:in require' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:229:inblock in require'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:214:in load_dependency' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:229:inrequire'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/engine.rb:591:in block (2 levels) in <class:Engine>' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/engine.rb:590:ineach'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/engine.rb:590:in block in <class:Engine>' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/initializable.rb:30:ininstance_exec'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/initializable.rb:30:in run' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/initializable.rb:55:inblock in run_initializers'
from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:150:in block in tsort_each' from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:183:inblock (2 levels) in each_strongly_connected_component'
from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:210:in block (2 levels) in each_strongly_connected_component_from' from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:219:ineach_strongly_connected_component_from'
from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:209:in block in each_strongly_connected_component_from' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/initializable.rb:44:ineach'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/initializable.rb:44:in tsort_each_child' from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:203:ineach_strongly_connected_component_from'
from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:182:in block in each_strongly_connected_component' from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:180:ineach'
from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:180:in each_strongly_connected_component' from /home/vagrant/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/tsort.rb:148:intsort_each'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/initializable.rb:54:in run_initializers' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/application.rb:215:ininitialize!'
from /home/vagrant/code/sample-milia-app/config/environment.rb:5:in <top (required)>' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:229:inrequire'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:229:in block in require' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:214:inload_dependency'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/activesupport-4.0.1/lib/active_support/dependencies.rb:229:in require' from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/application.rb:189:inrequire_environment!'
from /home/vagrant/.rvm/gems/ruby-2.0.0-p481@sample-milia-app/gems/railties-4.0.1/lib/rails/commands.rb:44:in <top (required)>' from bin/rails:4:inrequire'
from bin/rails:4:in `

'

rails 4 compatibility

I am trying to use milia with a new rails 4 project using the devise rails4 branch. When sign_up is called I am getting the following stack trace. I know it is due to the new strong attributes in Rails 4 - just not sure the best place to fix it.

ActiveModel::ForbiddenAttributesError - ActiveModel::ForbiddenAttributesError:
  (gem) activemodel-4.0.0.beta1/lib/active_model/forbidden_attributes_protection.rb:21:in `sanitize_for_mass_assignment'
  (gem) activerecord-4.0.0.beta1/lib/active_record/attribute_assignment.rb:21:in `assign_attributes'
  (gem) activerecord-4.0.0.beta1/lib/active_record/core.rb:174:in `initialize'
  (gem) activerecord-4.0.0.beta1/lib/active_record/inheritance.rb:24:in `new'
  /home/ed/.rvm/gems/ruby-2.0.0-rc2/bundler/gems/devise-ce37c301ff91/lib/devise/models/registerable.rb:20:in `new_with_session'
  /home/ed/.rvm/gems/ruby-2.0.0-rc2/bundler/gems/devise-ce37c301ff91/app/controllers/devise/registrations_controller.rb:87:in `build_resource'
  /home/ed/work/cluey/milia/app/controllers/registrations_controller.rb:72:in `devise_create'
  /home/ed/work/cluey/milia/app/controllers/registrations_controller.rb:29:in `block in create'
  (gem) activerecord-4.0.0.beta1/lib/active_record/connection_adapters/abstract/database_statements.rb:201:in `block in transaction'
  (gem) activerecord-4.0.0.beta1/lib/active_record/connection_adapters/abstract/database_statements.rb:209:in `within_new_transaction'
  (gem) activerecord-4.0.0.beta1/lib/active_record/connection_adapters/abstract/database_statements.rb:201:in `transaction'
  (gem) activerecord-4.0.0.beta1/lib/active_record/transactions.rb:209:in `transaction'
  /home/ed/work/cluey/milia/app/controllers/registrations_controller.rb:23:in `create'

Members can invite members

Hi,
I just installed and tried the new version of the app and it is working much better - thanks! One thing I did notice is that members can invite members, is this by design? I would think only organizational users should be able to invite members but maybe I am missing something. Thanks again!

Stephen

Milia & subdomains

Hi,

Great gem btw!

My question is about setting up subdomains for Milia, mainly the steps I should follow to get that implemented correctly ?

Thanks in advance!

Rails 4.1 compatibility

Hello,

When do you plan to release milia to be fully Rails 4.1 compatible?

We are upgrading to latest version of Rails, and the next step of our application will be to find a suitable multi tenancy gem. Currently, a con with this gem is the current Rails 4.0.x dependency.

Since this dependency is due to the web-app-theme, namely rails g web_app_theme:milia, and I plan to incorporate this into an existing application (not running the command at all) then I should be able to safely ignore the 4.0.x dependency by forking that gem and loosening the gemspec as per #34 - Am I correct?

Best regards,
Mathias

Need multitenancy across databases/schemas

Thanks for the awesome gem, it has helped us to bootstrap our app with multitenancy. This is ok with our initial development but we would need this to be supported across multiple databases/schemas. Do you have any plan to develop Milia on this line in near future?

uninitialized constant Control

Hello,

I'm using:
devise (2.2.4)
milia (0.3.30)
Rails 3.2.12
ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-darwin10.8.0]

I've tried to follow your tutorial, but upon user creation I get:

uninitialized constant Control

below the log:

Started POST "/users" for 127.0.0.1 at 2013-06-06 12:02:49 +0200
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"8uZpO5HRLvkhxsrhUfZzq3i710po/AnngI1VZJeOZ70=", "user"=>{"username"=>"", "email"=>"[cut]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
(0.1ms) begin transaction
User Exists (0.4ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = '[cut]' LIMIT 1
SQL (0.7ms) INSERT INTO "tenants" ("created_at", "name", "tenant_id", "updated_at") VALUES (?, ?, ?, ?) ["created_at", Thu, 06 Jun 2013 12:02:49 CEST +02:00], ["name", :username], ["tenant_id", nil], ["updated_at", Thu, 06 Jun 2013 12:02:49 CEST +02:00] rollback transaction
Completed 500 Internal Server Error in 70ms

NameError (uninitialized constant Control):
milia (0.3.30) lib/milia/base.rb:61:in block in acts_as_universal' activesupport (3.2.8) lib/active_support/callbacks.rb:440:in_run__3560432618853441863__save__2851447896423817079__callbacks'
activesupport (3.2.8) lib/active_support/callbacks.rb:405:in __run_callback' activesupport (3.2.8) lib/active_support/callbacks.rb:385:in_run_save_callbacks'
activesupport (3.2.8) lib/active_support/callbacks.rb:81:in run_callbacks' activerecord (3.2.8) lib/active_record/callbacks.rb:264:increate_or_update'
activerecord (3.2.8) lib/active_record/persistence.rb:84:in save' activerecord (3.2.8) lib/active_record/validations.rb:50:insave'
activerecord (3.2.8) lib/active_record/attribute_methods/dirty.rb:22:in save' activerecord (3.2.8) lib/active_record/transactions.rb:241:inblock (2 levels) in save'
activerecord (3.2.8) lib/active_record/transactions.rb:295:in block in with_transaction_returning_status' activerecord (3.2.8) lib/active_record/connection_adapters/abstract/database_statements.rb:192:intransaction'
activerecord (3.2.8) lib/active_record/transactions.rb:208:in transaction' activerecord (3.2.8) lib/active_record/transactions.rb:293:inwith_transaction_returning_status'
activerecord (3.2.8) lib/active_record/transactions.rb:241:in block in save' activerecord (3.2.8) lib/active_record/transactions.rb:252:inrollback_active_record_state!'
activerecord (3.2.8) lib/active_record/transactions.rb:240:in save' devise (2.2.4) app/controllers/devise/registrations_controller.rb:15:increate'
actionpack (3.2.8) lib/action_controller/metal/implicit_render.rb:4:in send_action' actionpack (3.2.8) lib/abstract_controller/base.rb:167:inprocess_action'
actionpack (3.2.8) lib/action_controller/metal/rendering.rb:10:in process_action' actionpack (3.2.8) lib/abstract_controller/callbacks.rb:18:inblock in process_action'
activesupport (3.2.8) lib/active_support/callbacks.rb:458:in `_run__4479752414565192415__process_action__2670286493514513815__callbacks'
[cut].....

user tenant_id is always nil... is this right?

Title says it all really. My User model is set to acts_as_universal_and_determines_account

I'm trying to figure out how to know which users belong to which tenants (for other code).

Is this a problem with my configuration? Is there some other way to figure out this association?

Heroku crashes on display of sign_up page

Hi, I followed the setup instructions and I used the Milia and web-theme generators. Everything works on my local copy, except heroku crashes when I navigate to the Sign Up page.

Is this a known issue?

 Started GET "/users/sign_up" for 24.45.239.219 at 2014-03-09 16:45:45 +0000
 Processing by Milia::RegistrationsController#new as HTML
   Rendered devise/registrations/new.html.haml within layouts/sign (8.8ms)
 Completed 500 Internal Server Error in 14ms
 ActionView::Template::Error (First argument in form cannot contain nil or be empty):

           %p= message
     = form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :class => "form" }) do |f|
- flash.clear  # clear contents so we won't see it again

  = devise_error_messages!
    = f.label :email, :class => "label"


  .group

milia with 'simple_token_authentication' gem

Im using Milia and trying to integrate token authentication with 'simple_token_authentication' gem, but it doesn't seem to work. Is it possible at all to use an API with token authentication in combination with milia ? Thanks

milia:install giving error

I am trying to get 1.0.0-beta-3 installed right now, and with a fresh application I get this when I try a rails g milia:install --org_email='[email protected]':

<path>/milia-db26774ebc67/app/controllers/registrations_controller.rb:3:in `<module:Milia>': uninitialized constant Milia::Devise (NameError)

Is this something I am doing wrong or is there a bug somewhere?

Thanks.

Invited user confirmation link fails with missing ActionView::MissingTemplate error

Using Milia 1.0.0 with Rails 4.1.5. The "invite user" method sends out an email with a confirmation link like:

http://localhost:3000/users/confirmation?confirmation_token=RxCpy4xz955ymQmL3txK

Clicking this link generates an error:

ActionView::MissingTemplate (Missing template milia/confirmations/show, devise/confirmations/show, devise/show, application/show with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee, :haml]}.

I don't see a confirmations#show view anywhere in milia or devise. Looking at the source for https://github.com/dsaronin/milia/blob/master/app/controllers/confirmations_controller.rb I see this comment at line 56:

# else fall thru to show template which is form to set a password
# upon SUBMIT, processing will continue from update

Where should the confirmations#show template be coming from?

v0.3.38 dependency on Rails 3.2.13

Hi David,

First, thanks for your work on this gem. It works very well and is much appreciated.

I'm working on updating my app to the latest point release of Rails (3.2.17 at the moment) to pick up the security fixes. Milia v0.3.38 has a dependency on rails = 3.2.13. Is there a reason this is not rails ~> 3.2.13?

Rails 5 support

Did you test milia with Rails 5 already or do you have plans to do so?

failure to destroy associated models

in my tenant I have put the following line:

has_many :monthly_order_summaries, dependent: :destroy

When I destroy the tenant I see this in my logs:

MonthlyOrderSummary Load (0.2ms) SELECT monthly_order_summaries.* FROM monthly_order_summaries WHERE (monthly_order_summaries.tenant_id = NULL) ANDmonthly_order_summaries.tenant_id = 16

Obviously this will not work - it is ANDing on two tenant_id selects.

The model looks like this:

class MonthlyOrderSummary < ActiveRecord::Base acts_as_tenant end

This happens if I do:

Tenant.last.destroy

Sample Milia app isn't passing a tenant param?

I followed the sample app with Rails 4.2 and Ruby 2.1.5 and when I get to the signup page and submit I see the following stack trace in the error.

There is no tenant param being passed, and it's apparently required. I made sure I didn't miss a step, it's a brand new database with nothing in it, it's a brand new app without any modifications to the step-by-step instructions other than what's mentioned above with Ruby and Rails.

Any advice?

11:24:29 web.1  | Processing by Milia::RegistrationsController#create as HTML
11:24:29 web.1  |   Parameters: {"utf8"=>"✓", "authenticity_token"=>"ReCQQiaS3UchSGJRxf1BjLzi84wjGUoq6VFdIzYWgWmD5NyYFXFtteqMoSLA0/0GNMLwRth3+qLguBv3b50Byw==", "user"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
11:24:29 web.1  | Completed 400 Bad Request in 2ms (ActiveRecord: 0.0ms)
11:24:29 web.1  |
11:24:29 web.1  | ActionController::ParameterMissing (param is missing or the value is empty: tenant):

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.