简体   繁体   中英

Cannot loop through a rails hash

I'm working on a legacy app and I'm refactoring the settings, we have a strange db structure but it can't be changed due to existing data.

The issue I'm having is the following, the settings are created using a db:seed which is fine, however, I cannot then go into the form and update them.

Here's what I have so far (files cut down for length)

The form is on the index so I've moved everything over to that method and I've commented out all of the legacy code

controller

class SettingsController < ApplicationController
  load_and_authorize_resource
  before_action :authenticate_user!
  respond_to :json, :html

  def index
    # all_params_permitted
    # strip_list = [
    #   'company_main_mail',
    #   'company_accounts_mail',
    #   'company_web_site',
    #   'company_vat_number'
    # ]
    # @errors = []
    # @error_list = []
    # @settings = params[:settings].each do |index, value|
    #   setting = Setting.find_by(name: index)
    #   if setting
    #     setting.value = value
    #   end
    #   setting.save
    # end
    # params[:settings].each do |index, value|
    #   setting = Setting.find_by(name: index)
    #   if setting
    #     if strip_list.include? setting.name
    #       setting.value = value.strip
    #     else
    #       setting.value = value
    #     end
    #     setting.save
    #     if setting.errors.present?
    #       @errors << setting
    #       @error_list << {name: setting.name , value: value}
    #     end
    #   end
    # end
    # check_boxes = [
    #   'company_incorporation_status',
    #   'company_vat_status',
    #   'is_vso',
    #   'is_efpm',
    #   'exclude_non-manufactured_from_wo_creation_from_so',
    #   'check_stock_levels',
    #   'show_vat_on_uninvoiced_sales',
    #   'hide_due_date_on_sales_quotes_and_orders',
    #   'hide_due_date_on_purchase_quotes_and_orders',
    #   'kpi_use_average_cos',
    #   'kpi_use_average_labour',
    #   'discounts_enabled',
    #   'remove_works_order_from_plan_after_edit',
    #   'user_change_own_password',
    #   'auto_populate_receive_invoice',
    #   'assume_supplier_has_vat_number_for_auto_populate_receive_invoice',
    #   'enable_comments_on_stock_components',
    #   'default_true_create_supply_orders',
    #   'sales_order_item_custom_info_1_enabled',
    #   'update_probability_on_opportunity_status_change',
    #   'no_supplier_serial_numbers',
    #   'enable_batch_number_generation',
    #   'include_sales_order_notes_on_picking_lists',
    #   'backorder_default',
    #   'consolidate_work_order',
    #   'over_delivery_default',
    #   'restrict_purchase_invoice_query_flag',
    #   'use_package_lines',
    #   'hightlight_below_order_quantity_on_grn',
    #   'show_poi_descriptions_on_order_lines',
    #   'intrastat_enable',
    #   'intrastat_enable_tod',
    #   'api_enabled',
    #   'wo_process_start_time',
    #   'negative_current_stock',
    #   'btp_enabled',
    #   'enable_custom_documents',
    #   'vat_adjustment_limit',
    #   'cash_accounting',
    #   'is_northern_ireland_protocol'
    # ]
    # check_boxes.each do |box|
    #   if !params[:settings][box]
    #     setting = Setting.find_by_name(box)
    #     if setting
    #       setting.value = 0
    #       setting.save
    #     end
    #   end
    # end
    # params[:large_settings].each do |index, value|
    #   setting = LargeSetting.find_by_name(index)
    #   if setting
    #     setting.value = value
    #     setting.save
    #   end
    # end
    # if params[:company_logo]
    #   @company_logo = Image.find_by_code('LOGO')
    #   @company_logo.update_attributes(params[:company_logo])
    # end
    # if params[:factoring_image]
    #   @factoring_image = Image.find_by_code('FACTORING')
    #   @factoring_image.update_attributes(params[:factoring_image])
    # end
    # if (@factoring_image && @factoring_image.errors && @factoring_image.errors.size > 0) || (@company_logo && @company_logo.errors && @company_logo.errors.size > 0) || (@errors.size > 0)
    #   @settings = get_settings(true)
    #   if @error_list.size > 0
    #     @error_list.each do |error|
    #       @settings[error[:name]] = error[:value]
    #     end
    #   end
    #   render settings_path
    # else
    #   redirect_to settings_path
    # end
  end

  private

  def setting_params
    params.require(:setting).permit(
      :name,
      :value,
      :value_type
    )
  end
end

form

<div class="l-12col" id="settings_form">
  <%= form_for @settings, method: :post, multipart: true do |f| %>
    <%# post_code %>
    <div class="tabs">
      <!-- start tab headings -->
      <div class="tab-headings">
        <a class="tab-button active" data-id="company_details">Company Details</a>
        <a class="tab-button" data-id="tax_payroll">Tax &amp; Payroll</a>
        <a class="tab-button" data-id="system_settings">System Settings</a>
        <a class="tab-button" data-id="trade_terms">Trade Terms</a>
        <a class="tab-button" data-id="factoring">Factoring</a>
        <a class="tab-button" data-id="document_storage">Document Storage</a>
        <% if Features.API? %>
          <a class="tab-button" data-id="web_api">Web API</a>
        <% end %>
      </div>
      <!-- end tab headings -->
      <div class="tab-contents">
        <!-- start of company_details tab -->
        <div class="tab-content active" id="company_details">
          <div class="l-row-block clearfix">
            <div class="l-06col l-ml-12col l-md-12col">
              <h2 class="txt-title-alt">
                Name &amp; Address
                <span data-tooltip title="Full legal name and address for this business as it should appear on business documentation.">
                  <span class="icon-help-with-circle" aria-hidden="true"></span>
                </span>
              </h2>
              <div class='field l-margin-sm'>
                <%= f.label :company_name %>
                <%= f.text_field :company_name %>
              </div>
              <div class='field l-margin-sm'>
                <%= f.label :company_system_display_name %>
                <%= f.text_field :company_system_display_name %>
              </div>
              <div class='field l-margin-sm'>
                <%= f.label :company_address_1, "Address Line 1" %>
                <%= f.text_field :company_address_1 %>
              </div>
              ...
            </div>
          </div>
        </div>
        <!-- end of company_details tab -->
        ...
      </div>
    </div>

    <div class="btns">
      <%= submit_tag "Update", id: 'company_settings_update_btn' %>
      <%= link_to "Cancel", root_path, class: "btn-medium" %>
    </div>
  <% end %>
</div>

Here is what the db table looks like在此处输入图片说明

As a test here is what t I've tried.

I added @settings = Setting.new to the index which then gave me an undefined method error so in the model I added the following

def company_name
  Setting.find_by(name: :company_name).value
end

which rendered the page with the correct company name, however, there are 135 settings so I need a way to save all of them.

I would recommend you to add a class method on your model:

def self.value_for(setting)
  Setting.find_by(name: setting).try(:value)
end

And set the value attribute on your fields:

f.text_field :company_name, value: Setting.value_for(:company_name)
f.number_field :quote_value, value: Setting.value_for(:quote_value)

It's not perfect but it's very clear and readable, which is important in legacy code

In the controller something like that should do the job:

def update
  # Do some checks if you want

  params[:settings].each do |setting, value|
    next if unallowed_setting(setting) # create unallowed_setting method if you need a filter, remove this line otherwise

    model = Setting.find_or_initialize_by(name: setting)
    model.value = value
    model.save!
  end

  redirect_to :index
end

EDIT

Another possibility would be to keep you old code and set @settings to an OpenStruct instance so you won't have to set value in view, but I'm not 100% sure it will work:

def index
  settings = {
    id: nil # I think this would be needed
  }
  Setting.all.each do |setting|
    settings[setting.name] = setting.value
  end
  @settings = OpenStruct.new(settings)
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM