Models
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :roles, :dependent => :destroy, :inverse_of => :user
has_many :companies, :through => :roles
accepts_nested_attributes_for :roles, :limit => 1, :allow_destroy => true
end
class Role < ActiveRecord::Base
belongs_to :user, :inverse_of => :roles
belongs_to :company, :inverse_of => :roles
accepts_nested_attributes_for :company
end
class Company < ActiveRecord::Base
has_many :roles, :dependent => :destroy, :inverse_of => :user
has_many :users, :through => :roles
validates :name, presence: true
end
Custom Devise Registration Controller
class RegistrationsController < Devise::RegistrationsController
# GET /resource/sign_up
def new
build_resource({})
@role = resource.roles.build(role: "owner", active: 1, default_role: 1)
@company = @role.build_company
set_minimum_password_length
yield resource if block_given?
respond_with self.resource
end
protected
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation, roles_attributes: [ company_attributes: [ :id, :name ] ] )
end
end
HTML
<%= form_for(resource, :html => {:class => "form-signin" }, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render partial: "shared/flash" %>
<%= devise_error_messages! %>
<h1 class="form-signin-heading text-muted">Register</h1>
<%= f.email_field :email, class: "form-control", placeholder: "Email", autofocus: true %>
<%= f.password_field :password, class: "form-control", placeholder: "Password", autocomplete: "off" %>
<%= f.password_field :password_confirmation, class: "form-control", placeholder: "Password Confirmation", autocomplete: "off" %>
<%= f.fields_for :roles, resource.roles.build do |r| %>
<%= r.fields_for :company, resource.roles.build.build_company do |c| %>
<%= c.text_field :name, class: "form-control", placeholder: "Company", autocomplete: "off" %>
<% end %>
<% end %>
<button class="btn btn-lg btn-primary btn-block" type="submit">
Register
</button>
<% end %>
This works - my intermediate Role is created with the id_user and id_company. The problem is I want to set the some additional fields in the newly created Role. for example I have a :role column that I want to set to 'owner' as this is the a brand new company and the user that signed up is the owner.
I want to do this in the controller to prevent any mass assignment issues from the user submitted form.
Do I need to set this somehow in the custom devise registration controller and create a full custom create action?
I admit I am likely not explaining this well as I am a bit of a newbie on the whole nested forms and active record etc.
UPDATE
It's not pretty but I just pasted this at the end of my new controller:
def set_minimum_password_length
if devise_mapping.validatable?
@minimum_password_length = resource_class.password_length.min
end
end
UPDATE 2
I had copied the master code vs the current version code. Once I fixed that it's all good.
I would overwrite the create action so that you can hardcode (and the user can't mess with) the role attributes.
You're assigning them in the new action, but you'd need to have hidden fields so they get passed to create and persist into the database. However, that's not a good idea because anyone can edit the HTML and change those values. It's better to do this in the create action instead like so: