-1

I would like to add a shop in the user registration with Devise.

Let me explain: on the registration page, the user can check a box "create my shop now." If he checks, a form is displayed ans he can fill it. Then he submits the form, and User + Shop creates. I'd like to know the best method in the controller "UsersController", as well as models and views.

Thank you for your help

UPDATE : Here is my code

app/views/devise/registrations/new.html.haml :

#sign_up
  %h2 Create your account

  = simple_form_for resource, as: resource_name, url: registration_path(resource_name) do |f|
    = f.error_notification

    = f.input :email, autofocus: true, input_html: { class: 'input-block-level' }
    = f.input :password, input_html: { class: 'input-block-level' }

    #check_box_fields
      = check_box_tag :create_shop_now, nil, nil, data: { toggle: 'collapse', target: '#shop_part' }
      = label_tag :create_shop_now, "I want a shop !" , class: 'checkbox inline'

    #shop_part.collapse
      = f.simple_fields_for :shops do |s|
        = s.input :name
        = s.input :email
        = s.input :description
        = s.input :siren

    #submit= f.button :submit, "Sign up", class: 'btn btn-primary'
    %p By clicking on 'Sign up', you confirm that you accept the Terms of Use

app/controllers/users/registrations_controller.rb :

class Users::RegistrationsController < Devise::RegistrationsController
  def create
    # raise params.inspect
    build_resource

    if resource.save
      if params[:user][:create_shop_now]
        resource.shops << Shop.create(params[:user][:shops_attributes])
      end

      if resource.active_for_authentication?
        set_flash_message :notice, :signed_up if is_navigational_format?
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
        expire_session_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      respond_with resource
    end
  end
end

app/models/user.rb :

class User < ActiveRecord::Base
  rolify

  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :email, :password, :password_confirmation, :remember_me,
              :first_name, :last_name, :birthday, :gender_cd, :shops_attributes

  validates_presence_of :password
  validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, on: :create }
  validates_presence_of :email

  has_many :assignments, dependent: :destroy
  has_many :shops, through: :assignments

  accepts_nested_attributes_for :shops

  after_initialize do
    shops.new
  end
end

UPDATE 2 : Here is working code

app/views/devise/registrations/new.html.haml

#sign_up
  %h2 Create your account

  = simple_form_for resource, as: resource_name, url: registration_path(resource_name) do |f|
    = f.error_notification

    = f.input :email, autofocus: true, input_html: { class: 'input-block-level' }
    = f.input :password, input_html: { class: 'input-block-level' }

    #check_box_fields
      = check_box_tag :create_shop_now, nil, nil, data: { toggle: 'collapse', target: '#shop_part' }
      = label_tag :create_shop_now, "I want a shop !" , class: 'checkbox inline'

    #shop_part.collapse
      = f.simple_fields_for :shops do |s|
        = s.input :name
        = s.input :email
        = s.input :description
        = s.input :siren

    #submit= f.button :submit, "Sign up", class: 'btn btn-primary'
    %p By clicking on 'Sign up', you confirm that you accept the Terms of Use

app/controllers/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController

  def new
    resource = build_resource({})
    resource.shops.build
    respond_with resource
  end

  def create
    build_resource

    if resource.save
      if resource.active_for_authentication?
        set_flash_message :notice, :signed_up if is_navigational_format?
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
        expire_session_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      respond_with resource
    end
  end
end

app/models/user.rb

class User < ActiveRecord::Base
  rolify

  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :email, :password, :password_confirmation, :remember_me,
              :first_name, :last_name, :birthday, :gender_cd, :shops_attributes

  validates_presence_of :password
  validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, on: :create }
  validates_presence_of :email

  has_many :assignments, dependent: :destroy
  has_many :shops, through: :assignments

  accepts_nested_attributes_for :shops
end

1 Answers1

0

You can do this with accepts_nested_attributes_for and nested models.

Simple checkout

UPDATE:

add the shop attributes to the form (with fields_for => accepts_nested_attributes_for), hide these form fields. create an attr_accessor in your user model, for example called :create_shop_now, add this to your form. if :create_shop_now is checked, show the shop form fields..an user can fill in the fields. user submits the form to the create action. The create action could look like following:

def create
  build_resource

  if !params[:user][:create_show_now]
    params[:user].delete(:shops_attributes)
  end

  if resource.save
    if resource.active_for_authentication?
      set_flash_message :notice, :signed_up if is_navigational_format?
      sign_up(resource_name, resource)
      respond_with resource, :location => after_sign_up_path_for(resource)
    else
      set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
      expire_session_data_after_sign_in!
      respond_with resource, :location => after_inactive_sign_up_path_for(resource)
    end
  else
    clean_up_passwords resource
    respond_with resource
  end
end

UPDATE2

Remove your after_initialize hook in the model and update your registrations#new action to following:

def new
  resource = build_resource({})
  resource.shops.build
  respond_with resource
end
Matthias
  • 4,355
  • 2
  • 25
  • 34
  • It's not that. I'm searching what I have to insert in my models and controllers. In example, in the UsersController. Should I do `if resource.save if params[:user][:shops_attributes] resource.shops << Shop.new(params[:user][:shops_attributes]) end end` I'm searching the best method. Clean and working. I'm doing a v2 of a website so I try to do the best – Donovan BENFOUZARI May 07 '13 at 13:16
  • Thank you. So it hasn't easier way. But when I'm trying to do this, it creates 2 shops. One with filled fields, and one empty. I tried to remove my `after_initialize do shops.new end` but `form_for :shops` doesn't show fields ? – Donovan BENFOUZARI May 10 '13 at 10:31
  • I updated my answer. I think resource.save already creates a new shop, if the params are empty => an empty shop will be created. – Matthias May 10 '13 at 11:00
  • I tried to remove it, it works but it creates 2 shops when params are not empty – Donovan BENFOUZARI May 10 '13 at 11:05
  • try to remove your after_initialize hook - it could be possible, that the devise method "build_resource" already initializes a new shop too. – Matthias May 10 '13 at 11:09
  • As said before, when I remove my "after_initialize", "fields_for :shops" doesn't show fields. – Donovan BENFOUZARI May 10 '13 at 11:14
  • Ah okay, I updated my answer again, UPDATE2 - i think that you have to remove your after_initialize hook, because otherwise the devise method build_resource will initialize twice the User.new => and also twice the hook will be called.. but to avoid the error, you have to update your registrations#new action like in my answer described. – Matthias May 10 '13 at 11:20
  • Yeah, it works ! I will update my question with working code, thank you Matt ! :) – Donovan BENFOUZARI May 10 '13 at 11:23
  • Oh no... When user doesn't checks the checkbox and submits form, it creates an empty shop ? Because `resource.shops.build` ? I'm checking the checkbox with `if params[:user][:create_shop_now]`, and when I `raise params.inspect`, I have "{"utf8"=>"✓", "authenticity_token"=>"PvCjR9aQdcaHSG54izlwhHUMuhseb9ojars9/Zg015c=", "user"=>{"email"=>"d.benfouzari@gmail.com", "password"=>"test", "shops_attributes"=>{"0"=>{"name"=>"", "email"=>"", "description"=>"", "siren"=>""}}}, "commit"=>"Sign up", "action"=>"create", "controller"=>"users/registrations"}" – Donovan BENFOUZARI May 10 '13 at 11:44
  • take a look at my create action, and your updated create action from your question ;).. if !params[:user][:create_show_now] params[:user].delete(:shops_attributes) end => this part is missing at yours.. you have to delete the shop_attributes if not checked - otherwise an empty shop will be created.. – Matthias May 10 '13 at 11:45
  • Yes, was my fault. But even doing as you say, an empty shop is created, but params are correctly removed : {"utf8"=>"✓", "authenticity_token"=>"+X4NdXHlW/8ngkF/gIW9qIZV3TZXKpA2Dcf9dJSgOxA=", "user"=>{"email"=>"d.benfouzari@gmail.com", "password"=>"testlala"}, "commit"=>"Sign up", "action"=>"create", "controller"=>"users/registrations"} – Donovan BENFOUZARI May 10 '13 at 12:02
  • maybe you have to overwrite the build_resource method in your create and new action. check out the source code of the devise gem. the build_resource method is in the registrations_controller.rb file. maybe all could be solved with simple resource = User.new(params[:user] in your create action. – Matthias May 10 '13 at 12:07