ruby - 在数据库中传递并保存哈希作为强参数
问题描述
当我创建/更新记录时,我得到以下输出
Processing by ContactsController#create as HTML
Parameters: {..."custom_fields_attr"=>{"1"=>"testing cft", "2"=>"", "3"=>"", "4"=>""}}, "commit"=>"Create"}
但是,它似乎并没有保存到数据库,当记录保存时,它会影响三个表contacts
,custom_fields
并且custom_field_values
,联系人表很好,但是其他两个没有更新,所以哈希的关键是字段fromcustom_fields
并且值被存储或更新在custom_field_values
这是表单生成的内容
<div class="field l-margin-sm">
<label for="contact_custom_fields_attr_1">test</label>
<input type="text" name="contact[custom_fields_attr][1]" id="contact_custom_fields_attr_1" data-custom_field_id="1" data-mandatory="false">
</div>
我的控制器中有以下内容作为强大的参数
custom_fields_attr: {}
在每个模型中都有这样after_save :save_custom_fields_attr
的方法,application_record
所以我尝试将它直接添加到模型中,我得到了Unpermitted parameter: 1
,所以在我看来,after_save
没有被触发。
在我实现强参数之前,我们new. create
在控制器中的方法中有以下内容。
def new
all_params_permitted
@coontact = Contact.new(params[:contact])
end
all_params_permitted
是一种方法,application_controller
所以我目前正在尝试将其移至强参数,除哈希contacts_controller
外,一切正常。custom_fields_attr
contact.rb
(删除了一些不相关的方法)
class Contact < ApplicationRecord
belongs_to :customer, class_name: 'Customer', foreign_key: 'customer_account_id'
belongs_to :supplier, class_name: 'Supplier', foreign_key: 'supplier_account_id'
belongs_to :assignee, class_name: 'User', foreign_key: 'assigned_to'
has_many :events, dependent: :destroy
has_many :sales_quotes
has_many :sales_orders
has_many :support_tickets
has_many :estimates
has_many :leads, -> { where('lead is TRUE') }, class_name: 'Event', foreign_key: 'contact_id'
has_many :complaints, -> { where('complaint is TRUE') }, class_name: 'Event', foreign_key: 'contact_id'
has_many :general_notes, -> { order(created_at: :desc) }, as: :reference
has_many :interaction_notes, -> { order(created_at: :desc) }, foreign_key: 'contact_id'
has_many :non_complaint_events, -> { where(complaint: nil) }, class_name: 'Event', foreign_key: 'contact_id'
belongs_to :creator, class_name: 'User', foreign_key: 'created_by'
belongs_to :updater, class_name: 'User', foreign_key: 'updated_by'
has_many :opportunity_contacts
has_many :opportunities, through: :opportunity_contacts
has_one :anonymisation, as: :entity
validates_presence_of :name
validates_format_of :business_email, with: /(?:\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)|(\A\Z)/i
validates_format_of :private_email, with: /(?:\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)|(\A\Z)/i
acts_as_taggable_on :tags
include ActsAsTaggableOnExt::Core
TYPES = [
'Customer',
'Supplier',
'Customer and Supplier',
'Customer Prospect',
'Supplier Prospect',
'Customer and Supplier Prospect',
'Other'
]
PROSPECT_STRENGTHS = ['1 (strongest)', 1],
['2', 2],
['3', 3],
['4', 4],
['5', 5],
['6', 6],
['7', 7],
['8', 8],
['9 (weakest)', 9]
QUICK_SEARCH_FIELDS = {
name: {
column_names: 'contacts.name'
},
customers: {
joins_table: :customer,
column_names: 'contacts.name',
filters: { contact_type: 'customer' }
},
suppliers: {
joins_table: :supplier,
column_names: 'contacts.name',
filters: { contact_type: 'supplier' }
},
tags: {
tagged_with: true
}
}.with_indifferent_access
after_update :check_for_new_customer
attr_accessor :additional_validation, :row_number, :skip_this_validation
after_save :save_custom_fields_attr # what needs to get triggered
def self.default_controller
'contacts'
end
def default_controller
self.class.default_controller
end
validate :validate
def validate
if self.additional_validation
validate_for_custom_fields
end
end
...
end
contacts_controller.rb
(再次删除了一些降低长度的方法)
class ContactsController < ApplicationController
before_action :authenticate_user!
before_action :set_contact, only: [:show, :edit, :update, :remove_contact]
respond_to :json, :html
helper_method :sort_column, :sort_direction
...
def index
if params[:search].present?
@contacts = Contact.search(params[:qs], params[:search]).order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: 20)
else
@contacts = Contact.all.order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: 20)
end
end
def set_section
@section = 'crm'
end
protected :set_section
...
def show
@contact_complaints = Event.where(complaint: true, contact_id: @contact.id).order('id desc').limit(10)
@contact_leads = Event.where(lead: true, contact_id: @contact.id).order('id desc').limit(10)
@contact_events = Event.where(complaint: false, lead: false, contact_id: @contact.id).order('id desc').limit(10)
@contact_quotes = SalesQuote.where(contact_id: @contact.id).order('id desc').limit(10)
@contact_sales_orders = SalesOrder.where(contact_id: @contact.id).order('id desc').limit(10)
@contact_opportunities = @contact.get_contact_opportunities()
@contact_estimates = Estimate.where(contact_id: @contact.id).order('id desc').limit(10)
@support_tickets = SupportTicket.where(contact: @contact).limit(10)
@support_tickets = SupportTicket.where(contact: @contact).limit(10)
end
def new
@contact = Contact.new
@tags = ActsAsTaggableOn::Tag.all
if params[:l_tel]
@contact.phone = params[:l_tel]
end
if params[:customer] && customer = Customer.find(params[:customer])
@contact.customer = customer
end
if params[:supplier] && supplier = Supplier.find(params[:supplier])
@contact.supplier = supplier
end
render(action: 'new_remote', layout: false) if request.xhr?
end
def edit
@tags = ActsAsTaggableOn::Tag.all
end
def create
@contact = Contact.new(contact_params)
@contact.additional_validation = true
if @contact.save
if request.xhr?
render :create_remote, layout: false
else
render :index, notice: 'Contact was successfully created.'
end
else
if request.xhr?
render :new_remote, layout: false
else
render :new
end
end
end
def update
@contact.additional_validation = true
@tags = ActsAsTaggableOn::Tag.all
if @contact.update(contact_params)
flash[:notice] = 'Contact was successfully updated.'
redirect_to contacts_path
else
render :edit
end
end
...
protected
...
def set_contact
@contact = Contact.find(params[:id])
end
private
def sort_column
Contact.column_names.include?(params[:sort]) ? params[:sort] : 'id'
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
end
def contact_params
params.require(:contact).permit(
:customer_account_id,
:supplier_account_id,
:other_information,
:prospect_strength,
:business_email,
:private_email,
:date_of_birth,
:second_phone,
:company_name,
:contact_type,
:assigned_to,
:web_address,
:created_at,
:updated_at,
:salutation,
:created_by,
:updated_by,
:address_1,
:address_2,
:address_3,
:address_4,
:job_title,
:postcode,
:obsolete,
:mobile,
:spouse,
:phone,
:name,
:url,
tag_list: [],
custom_fields_attr: {}
)
end
end
如上所述的方法application_record
是这个
def save_custom_fields_attr
if @posted_custom_fields
values_h = self.custom_field_values_non_assoc_h
context = nil
context = self.get_custom_field_record_type_context if self.respond_to?('get_custom_field_record_type_context', true)
self.class.custom_fields(context).each do |cf|
posted_value = @posted_custom_fields[cf.id.to_s]
if cf.input_type == 'time' && posted_value.respond_to?('strip', true)
posted_value = posted_value.strip
end
cfv = values_h[cf.id.to_s]
if !cfv && posted_value.present?
cfv = CustomFieldValue.new({
custom_field_id: cf.id,
record_type: self.custom_field_record_type,
record_id: self.id
})
end
if posted_value.present?
cfv.value = posted_value
cfv.save
elsif cfv
cfv.destroy
end
end
end
end