Rails 4 Невозможно получить доступ к хешу во вложенной форме (неопределенный метод `[] 'для nil: NilClass)

Я построил довольно сложную форму, которая создает один рецепт с множеством реализаций. Я использую этот синтаксис:

- provide(:title, 'Create prescription')
%h1 Add medicines to prescription
.row
  .span6.offset3
    = form_for @prescription do |f|
      = render 'shared/error_prescription_messages'
      %p
        = f.hidden_field :patient_id, :value => params[:patient_id]
        = f.hidden_field :user_id, :value => current_user.id
      = f.fields_for :relations do |builder|
        = render 'child_form', :f => builder
      %p= f.submit "Submit"

chlid_form довольно прост:

- it=f.options[:child_index].to_i
- n= it.to_s

%h2
  = "Medicine ##{it+1}"

= f.hidden_field :medicine_id, :id => "my_medicine_id#{it}"
- if params[:prescription].nil? || params[:prescription][:relations_attributes][n.to_sym][:medicine_name].nil?
  = f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path, :id_element => "#my_medicine_id#{it}"
- else
  = f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path, :id_element => "#my_medicine_id#{it}", :value => params[:prescription][:relations_attributes][n.to_sym][:medicine_name]

= f.label :amount, "Amount of medicine boxes"
= f.number_field :amount, :value => 1

= f.label :daily
= f.number_field :daily, :value => 1

= f.label :period_in_days, "Duration of treatment (in days)"
= f.number_field :period_in_days, :value => 1

Итак, как вы можете видеть, я использую f.options[:child_index] для получения индекса дочернего элемента (0,1,2 ...), потому что я генерирую несколько элементов с этой конкретной формой. Затем я помещаю его в переменную it и успешно использую в :id_element => "#my_medicine_id#{it}", который отлично работает (создает my_medicine_id0, my_medicine_id1 ....) Хотя в этой строке он не работает:

:value => params[:prescription][:relations_attributes][n.to_sym][:medicine_name]

где n просто n=it.to_s.

Я хотя что-то не так в контроллере, но если я изменю эту строку на любое :value => params[:prescription][:relations_attributes]**[:'0']**[:medicine_name] или любое другое целое число от 0 до 4, все будет отлично работать, но мне НУЖНО динамическое изменение в этом. Итак, я получил доказательство того, что он ДЕЙСТВИТЕЛЬНО работает, потому что здесь он генерирует целочисленное значение "#my_medicine_id#{it}", но не будет работать в хэше! И когда я печатаю весь хеш из параметров, я получаю следующее:

{"patient_id"=>"7", "user_id"=>"1", "relations_attributes"=>{"0"=>{"medicine_id"=>"13490", "medicine_name"=>"Locacid 500 mcg/g (0,05%) (1 tuba 30 g)", "amount"=>"0", "daily"=>"1", "period_in_days"=>"1"}, "1"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "2"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "3"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "4"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}}}

поэтому для получения нужных мне значений совершенно очевидно, что params[:prescription][:relations_attributes][SOME_KIND_OF_INETEGER][:medicine_name] должен работать, но не работает.

Код контроллера:

class PrescriptionsController < ApplicationController
before_action :signed_in_user
before_action :doctor_user,     only: [:new, :create]
before_action :pharmacist_user, only: [:update]

def new
    @prescription =Prescription.new
    5.times { @prescription.relations.build }
end

def create
    @prescription = Prescription.new(new_prescription_params)
    if @prescription.save
        flash[:success] = "Prescription created."
        redirect_to @prescription
else
  5.times { @prescription.relations.build }
        render 'new', :prescription => params[:prescription]
    end
end

def show
    @prescription = Prescription.find(params[:id])
    @medicines = @prescription.medicines.paginate(page: params[:page], :per_page => 10)
end

def update
    @prescription = Prescription.find(params[:id])
    @patient = Patient.find(params[:patient_id])

    if !prescription_expired?(@prescription)
        @prescription.realized = 1
        if @prescription.save
            flash[:success] = "Prescription realized."
            redirect_to @patient
        else
            redirect_to root_url
        end
    else
            flash[:notice] = "Can't realize, prescription expired."
            redirect_to @patient
     end
end

private

    def new_prescription_params
      params.require(:prescription).
        permit(:patient_id, :user_id, relations_attributes: [:medicine_id, :medicine_name, :amount, :daily, :period_in_days])
    end 

    def doctor_user
      redirect_to(root_url) unless current_user.function == "doctor"
    end

    def pharmacist_user
      redirect_to(root_url) unless current_user.function == "pharmacist"
    end

    def prescription_expired?(presc)
        presc.created_at < 1.month.ago
    end

    def signed_in_user
        unless signed_in?
            store_location
            flash[:notice] = "Please log in."
            redirect_to login_url
        end
    end

конец

У меня кончились идеи, поэтому я прошу вас, ребята, может ли кто-нибудь помочь. Спасибо.


person Herwish    schedule 24.05.2014    source источник
comment
Это не похоже на рельсы. Почему вы связываете элементы формы с моделью, а затем переопределяете значения этого атрибута? Это нужно делать в контроллере. Обновите свой вопрос кодом контроллера, чтобы мы его исправили.   -  person BroiSatse    schedule 24.05.2014
comment
Я не уверен, почему вы делаете [n.to_sym] ... Я думаю, [n] сработает, не так ли? Это не символ в хеш-дампе.   -  person SteveTurczyn    schedule 24.05.2014
comment
Не пишите ничего личного. Прискорбно читать, как кто-то утверждает, что он разочарован. Это не имеет отношения к вопросу. И часто новички пишут такие слова, как странное / странное поведение, но в большинстве случаев в языке / фреймворке нет ничего странного или странного, и, скорее всего, это мышление тех людей, которые утверждают, что это странно.   -  person sawa    schedule 24.05.2014
comment
@SteveTurczyn [n] не работает, я пробовал много вариантов, например: # {n}, и множество разных вещей.   -  person Herwish    schedule 24.05.2014
comment
@BroiSatse Я добавил код контроллера.   -  person Herwish    schedule 24.05.2014


Ответы (1)


На ваш взгляд, нет смысла использовать params, поскольку вы уже назначили их своим моделям. Кроме того, при рендеринге нового действия эти параметры не существуют, поскольку на сервер еще ничего не было отправлено. Просто избавьтесь от всего values из входов.

Ваш партиал должен выглядеть так:

- it=f.options[:child_index].to_i
- n= it.to_s

%h2
  = "Medicine ##{it+1}"

= f.hidden_field :medicine_id, :id => "my_medicine_id#{it}"
= f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path

= f.label :amount, "Amount of medicine boxes"
= f.number_field :amount

= f.label :daily
= f.number_field :daily

= f.label :period_in_days, "Duration of treatment (in days)"
= f.number_field :period_in_days

Если вы хотите, чтобы ваши поля имели значение по умолчанию, установите значение по умолчанию в своей базе данных.

person BroiSatse    schedule 24.05.2014
comment
@Herwish - Значения по умолчанию - это определенно модельная вещь, а не контроллер и определенно не представление. TBH, я никогда не находил использования параметра value. Как я уже упоминал в нижней части ответа, установите значение по умолчанию в столбце базы данных или добавьте крючок after_initialize в свою модель. - person BroiSatse; 24.05.2014
comment
Вместо @prescription = Prescription.new сделайте @prescription = patient.find(parms[:patient_id]).prescriptions.build - person BroiSatse; 24.05.2014
comment
@Herwish - избавься и от values и там. Сделайте @prescription = patient.find(parms[:patient_id]).prescriptions.build(user_id: current_user) - person BroiSatse; 24.05.2014
comment
Да, ваше решение отлично работает. Вероятно, мне нужно будет реорганизовать мой код в остальной части приложения, потому что, держу пари, я использовал плохие решения в нескольких местах. В любом случае, это мой первый проект в RoR, и мне еще нужно многому научиться, поэтому спасибо за терпение @BroiSatse - person Herwish; 24.05.2014
comment
Можете ли вы быстро посмотреть здесь stackoverflow.com/questions/23896389/? - person Herwish; 27.05.2014