christian christian - 6 months ago 13
Ruby Question

Error after migration from ERB to HAML

I used http://htmltohaml.com/ this to convert my ERB and there is some kind of problem.

The working ERB before the convert

<h3><%= t("admin.labels.employee") %> <%= content_tag(:span, employee_counter) %></h3>
<%
def create_validation_rules(field_rules)
Hash[field_rules.map do |rule|
next ["rule-#{rule[:name]}", rule[:value]] if rule[:value]
next ["msg-#{rule[:name]}", rule[:msg]] if rule[:msg]
end] if field_rules
end
%>
<div class="control-group form-controls">
<%= f.label :first_name, t("labels.name") %>
<%= f.text_field :first_name, placeholder: t("labels.first_name"), class: 'js-employeeName', id: "merchant_employees_attributes_#{index}_first_name", name: "merchant[employees_attributes][#{index}][first_name]", autocomplete: "off", maxlength: 50, size: nil, data: create_validation_rules(validations[:first_name]) %>
<%= f.text_field :middle_name, placeholder: t("labels.middle_name"), id: "merchant_employees_attributes_#{index}_middle_name", name: "merchant[employees_attributes][#{index}][middle_name]", autocomplete: "off", maxlength: 100, size: nil %>
<%= f.text_field :last_name, placeholder: t("labels.last_name"), class: 'js-employeeName', id: "merchant_employees_attributes_#{index}_last_name", name: "merchant[employees_attributes][#{index}][last_name]", autocomplete: "off", maxlength: 50, size: nil, data: create_validation_rules(validations[:last_name]) %>
</div>
<div class="control-group">
<%= f.label :email, t("labels.email_address") %>
<%= f.text_field :email, id: "merchant_employees_attributes_#{index}_email", name: "merchant[employees_attributes][#{index}][email]", autocomplete: "off", maxlength: 250, size: nil, data: create_validation_rules(validations[:email]) %>
</div>
<div class="control-group">
<% if force_superuser_role %>
<%= f.hidden_field :superuser, value: "1" %>
<% else %>
<%= f.label :superuser, t("admin.labels.superuser") %>
<%= f.check_box :superuser, class: "superuser_checkbox", id: "merchant_employees_attributes_#{index}_superuser", name: "merchant[employees_attributes][#{index}][superuser]"%>
<% end %>
</div>


Not working HAML after the convert:

This is my error:
Showing /Users/project/app/views/shared/_employee.html.haml where line #9 raised:

%h3
= t("admin.labels.employee")
= content_tag(:span, employee_counter)
- def create_validation_rules(field_rules)
- Hash[field_rules.map do |rule|
- next ["rule-#{rule[:name]}", rule[:value]] if rule[:value]
- next ["msg-#{rule[:name]}", rule[:msg]] if rule[:msg]
- end] if field_rules
- end
.control-group.form-controls
= f.label :first_name, t("labels.name")
= f.text_field :first_name, placeholder: t("labels.first_name"), class: 'js-employeeName', id: "merchant_employees_attributes_#{index}_first_name", name: "merchant[employees_attributes][#{index}][first_name]", autocomplete: "off", maxlength: 50, size: nil, data: create_validation_rules(validations[:first_name])
= f.text_field :middle_name, placeholder: t("labels.middle_name"), id: "merchant_employees_attributes_#{index}_middle_name", name: "merchant[employees_attributes][#{index}][middle_name]", autocomplete: "off", maxlength: 100, size: nil
= f.text_field :last_name, placeholder: t("labels.last_name"), class: 'js-employeeName', id: "merchant_employees_attributes_#{index}_last_name", name: "merchant[employees_attributes][#{index}][last_name]", autocomplete: "off", maxlength: 50, size: nil, data: create_validation_rules(validations[:last_name])
.control-group
= f.label :email, t("labels.email_address")
= f.text_field :email, id: "merchant_employees_attributes_#{index}_email", name: "merchant[employees_attributes][#{index}][email]", autocomplete: "off", maxlength: 250, size: nil, data: create_validation_rules(validations[:email])
.control-group
- if force_superuser_role
= f.hidden_field :superuser, value: "1"
- else
= f.label :superuser, t("admin.labels.superuser")
= f.check_box :superuser, class: "superuser_checkbox", id: "merchant_employees_attributes_#{index}_superuser", name: "merchant[employees_attributes][#{index}][superuser]"

Answer

The correct way to handle this is to define the method as a helper in your controller:

class MyController
  helper_method :create_validation_rules

private
  def create_validation_rules(field_rules)
    Hash[field_rules.map do |rule|
      next ["rule-#{rule[:name]}", rule[:value]] if rule[:value]
      next ["msg-#{rule[:name]}", rule[:msg]] if rule[:msg]
    end] if field_rules
  end
end

This will allow you to call create_validation_rules from within the view, without having to define the method there. See In Rails, what exactly do helper and helper_method do? to understand exactly what a helper method is and how it works.


However, if you simply must use an embedded method in the View code, there is a solution: you can simply eliminate the last end in the inline function, and properly indent the body of the function and the loop.

In this case, the error message would have explained everything:

You don't need to use "- end" in Haml. Un-indent to close a block

Updating your HAML code, this works:

%h3
  = t("admin.labels.employee")
  = content_tag(:span, employee_counter)
- def create_validation_rules(field_rules)
  - Hash[field_rules.map do |rule|
    - next ["rule-#{rule[:name]}", rule[:value]] if rule[:value]
    - next ["msg-#{rule[:name]}", rule[:msg]] if rule[:msg]
  - end] if field_rules
.control-group.form-controls
  = f.label :first_name, t("labels.name")
  = f.text_field :first_name, placeholder: t("labels.first_name"), class: 'js-employeeName', id: "merchant_employees_attributes_#{index}_first_name", name: "merchant[employees_attributes][#{index}][first_name]", autocomplete: "off", maxlength: 50, size: nil, data: create_validation_rules(validations[:first_name])
  = f.text_field :middle_name, placeholder: t("labels.middle_name"), id: "merchant_employees_attributes_#{index}_middle_name", name: "merchant[employees_attributes][#{index}][middle_name]", autocomplete: "off", maxlength: 100, size: nil
  = f.text_field :last_name, placeholder: t("labels.last_name"), class: 'js-employeeName', id: "merchant_employees_attributes_#{index}_last_name", name: "merchant[employees_attributes][#{index}][last_name]", autocomplete: "off", maxlength: 50, size: nil, data: create_validation_rules(validations[:last_name])
.control-group
  = f.label :email, t("labels.email_address")
  = f.text_field :email, id: "merchant_employees_attributes_#{index}_email", name: "merchant[employees_attributes][#{index}][email]", autocomplete: "off", maxlength: 250, size: nil, data: create_validation_rules(validations[:email])
.control-group
  - if force_superuser_role
    = f.hidden_field :superuser, value: "1"
  - else
    = f.label :superuser, t("admin.labels.superuser")
    = f.check_box :superuser, class: "superuser_checkbox", id: "merchant_employees_attributes_#{index}_superuser", name: "merchant[employees_attributes][#{index}][superuser]"

As a function definition embedded in ERB view code is abnormal, http://htmltohaml.com didn't handle it well, and simply regurgitated the entire method into the HAML output. While this is clearly incorrect, it's a simple matter to correct.


If you're being a good net citizen (and as you're already using the tool), you'll report this issue to the developer of http://htmltohaml.com so that he can account for this class of HAML generation issue.

Comments