mardi 14 juin 2016

How to work with two models on a single form where one model is read-only and second is editable (Rails 4)?

I use one signup form to enter data for two models: Tenant and User. Any tenant will have many users. When new user wants to signup he also enters data about his tenant (company). If entered tenant doesn't exist then new tenant is created along with new user. This part is working well. The problem is when new user enters the name of tenant that already exists in the database and ONLY if user will enter something wrong (for example, wrong email format). If something was entered wrong then validation error (for example, Email can't be blank) occurs AND all previously saved users of the same tenant are also displayed as a result of render 'new' in TenantController.

To display only the new record for which validation error was triggered I added <% if u.object.new_record? %> to the signup form:

  <%= f.fields_for(:users) do |u| %>
    <% if u.object.new_record? %>
    ...
    <% end %>
  <% end %>

In this case the signup form is displayed correctly, BUT when I correct the cause of the validation error (for example, enter correct email) and press Save button, then update action is executed instead of create action. And this is the problem, because I don't want any user to be able to update tenant data at signup stage. At signup user should be able to create only his personal data, not update his tenant's data. Please suggest the way to do this.

Tenant model:

class Tenant < ActiveRecord::Base

  has_many :users, dependent: :destroy, inverse_of: :tenant
  accepts_nested_attributes_for :users    

  before_validation do 
    self.status = 0 
    self.name = name_orig.upcase 
    email.downcase!
  end

  validates :name_orig, presence: true, length: { maximum: 255 }

  validates :name, uniqueness: { case_sensitive: false }

  VALID_EMAIL_REGEX = /A[w+-.]+@[a-zd-]+(.[a-zd-]+)*.[a-z]+z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }

  validates :status, presence: true

end

User model:

class User < ActiveRecord::Base

  belongs_to :tenant, inverse_of: :users

  before_validation do 
    self.status = 0
    self.email = email.downcase
  end

  validates :tenant, presence: true

  VALID_USERNAME_REGEX = /Aw+s?w*z/i
  validates :name,  presence: true, length: { maximum: 50 },
                    format: { with: VALID_USERNAME_REGEX },
                    uniqueness: { case_sensitive: false }

  VALID_EMAIL_REGEX = /A[w+-.]+@[a-zd-]+(.[a-zd-]+)*.[a-z]+z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }

  has_secure_password
  validates :password, presence: true, length: { minimum: 6 }

  validates :status, presence: true

end

Tenant controller:

class TenantsController < ApplicationController

  def show
    @tenant = Tenant.find(params[:id])
  end

  def new
    @tenant = Tenant.new
    @tenant.users.build
  end

  def create
    @tenant = Tenant.find_by(name: tenant_params[:name_orig].upcase)
    if @tenant == nil
      @tenant = Tenant.new(name_orig: tenant_params[:name_orig], 
                           email: tenant_params[:email])
      @user = @tenant.users.build(tenant_params[:users_attributes]["0"])
      @tenant.save
      if @tenant.save
        flash[:success] = "Welcome!"
        redirect_to @user   # redirects to user profile
      else
        render 'new'
      end
    else
      @user = @tenant.users.build(tenant_params[:users_attributes]["0"])
      if @user.save
        flash[:success] = "Welcome!"
        redirect_to @user   # redirects to user profile
      else
        render 'new'
      end
    end
  end   

  private

    def tenant_params
      params.require(:tenant).permit(:name_orig, :email,
          users_attributes: [:name, :email, :password, :password_confirmation])
    end
end

Signup form:

<%= form_for(@tenant) do |f| %>

  <%= render 'shared/tenant_error_messages' %>

  <%= f.label :name_orig, "Company name" %>
  <%= f.text_field :name_orig, class: 'form-control' %>

  <%= f.label :email, "Company e-mail" %>
  <%= f.email_field :email, class: 'form-control' %>

  <%= f.fields_for(:users) do |u| %>
    <% if u.object.new_record? %>
      <%= u.label :name, "User name" %>
      <%= u.text_field :name, class: 'form-control' %>

      <%= u.label :email, "User e-mail" %>
      <%= u.email_field :email, class: 'form-control' %>

      <%= u.label :password, "Password" %>
      <%= u.password_field :password, class: 'form-control' %>

      <%= u.label :password_confirmation, "Password confirmation" %>
      <%= u.password_field :password_confirmation, class: 'form-control' %>
    <% end %>
  <% end %>

  <%= f.submit "Save", class: "btn btn-primary" %>
<% end %>

Aucun commentaire:

Enregistrer un commentaire