1
votes

My forms are object-driven and work with form_for. I'm looking to achieve an /edit page for 1 object with 2 forms. More specifically, I'm looking to enable the user to change his password as well as to change his email on the same page. Depending which form has been submitted, the validations etc. should take the correct measures. So far I'm unable to do this.

I'm using Rails 4.

Problems: My validation Procs seem to be unable to detect mail-change / password-change (see hidden field in views) because I cannot use the hidden field in the Proc. So I have no way of detecting what type of form I'm submitting.

Please tell me if there's a more Rails like way of doing this cleanly and neatly or if the way is right and I'm just completely missing something.

Here are the files:

controllers/accounts_controller.rb

def edit
  set_pagedata('Account Informationen bearbeiten')
  @account = @current_user
end
def update
  @account = User.find(@current_user.id)

  if @account.update(account_params)
    redirect_to account_path
  else
    render 'edit'
  end
end

private

  def account_params
    params.require(:user).permit(:email, :email_confirmation, :password, :password_confirmation)
  end

models/user.rb

class User < ActiveRecord::Base
  has_one :admin
  has_many :customerships
  has_many :customers, :through => :customerships

  validates :salutation, presence: { message: 'Die Anrede wird benötigt!', if: :new_record? }
  validates :prename, presence: { message: 'Der Vorname wird benötigt!', if: :new_record? }
  validates :surname, presence: { message: 'Der Nachname wird benötigt!', if: :new_record? }
  validates :email,
    presence: { message: 'Die E-Mail Adresse wird benötigt!', if: Proc.new { | c | c.new_record? || c.email.present? } },
    uniqueness: { message: 'Diese E-Mail existiert bereits in unserem System!', if: Proc.new { | c | c.new_record? || c.email.present? } }
  validates :password,
    confirmation: { message: 'Das Passwort wiederholen Feld muss dem Passwort Feld entsprechen!', if: [:new_record?, :password_change?, '!password.nil?'] },
    length: { minimum: 5, maximum: 16, message: 'Das Passwort muss mindestens 5 und darf höchstens 16 Zeichen lang sein!', if: [:new_record?, :password_change?, '!password.nil?'] },
    presence: { message: 'Das Passwort wird benötigt!', if: [:new_record?, :password_change?, '!password.nil?'] }

  has_secure_password :validations => false

  def admin?
    Admin.find_by_user_id(self.id) != nil
  end

  def password_change?
    :edit_type == 'password-change'
  end
  def mail_change?
    :edit_type == 'mail-change'
  end
end

views/accounts/edit.html.erb

<div class="flash-stack">
    <%= "<p class='text-danger'>#{@account.errors.full_messages.first}</p>".html_safe if @account.errors.any? %>
</div>

<div class="mysd-panel">
    <div class="panel-heading">
        <h3 class="panel-title">E-Mail Adresse ändern</h3>
    </div>
    <div class="panel-body">
        <%= form_for @account, url: account_path, html: { :class => 'mysd-form' } do |f| %>
            <ul class="form-container">
                <li>
                    <%= f.text_field :email, :value => nil, :class => 'form-control', :placeholder => 'Neue E-Mail Adresse' %>
                </li>
                <li>
                    <%= f.text_field :password_confirmation, :value => nil, :class => 'form-control', :placeholder => 'Neue E-Mail Adresse wiederholen' %>
                </li>

                <%= f.hidden_field :edit_type, :value => 'password-change' %>
                <%= submit_tag 'Absenden', :class => 'mysd-btn btn-primary' %>
            </ul>
        <% end %>
    </div>
</div>


<div class="mysd-panel">
    <div class="panel-heading">
        <h3 class="panel-title">Passwort ändern</h3>
    </div>
    <div class="panel-body">
        <%= form_for @account, url: account_path, html: { :class => 'mysd-form' } do |f| %>
            <ul class="form-container">
                <li>
                    <%= f.password_field :password, :value => nil, :class => 'form-control', :placeholder => 'Neues Passwort' %>
                </li>
                <li>
                    <%= f.password_field :password_confirmation, :value => nil, :class => 'form-control', :placeholder => 'Neues Passwort wiederholen' %>
                </li>

                <%= f.hidden_field :edit_type, :value => 'mail-change' %>
                <%= f.submit 'Absenden', :class => 'mysd-btn btn-primary' %>
            </ul>
        <% end %>
    </div>
</div>
1
` :edit_type == 'password-change'` is comparing a string literal for a symbol - this will always be false. e - Frederick Cheung

1 Answers

0
votes

Rails way of doing this is to use just one form:

<%= form_for @account, url: account_path, html: { :class => 'mysd-form' } do |f| %>
            <ul class="form-container">
                <li>
                    <%= f.password_field :password, :value => nil, :class => 'form-control', :placeholder => 'Neues Passwort(leave blank if unchanged)' %>
                </li>
                <li>
                    <%= f.password_field :password_confirmation, :value => nil, :class => 'form-control', :placeholder => 'Neues Passwort wiederholen' %>
                </li>
<li>
                    <%= f.text_field :email, :value => @account.email, :class => 'form-control', :placeholder => 'Neue E-Mail Adresse' %>
                </li>

                <%= f.submit 'Absenden', :class => 'mysd-btn btn-primary' %>
            </ul>
        <% end %>

So any particular reason you are using two forms?