2017-02-21 43 views
3

Я новичок в Rails. Я пытаюсь создать приложение, в котором учащиеся могут войти в систему и зарегистрироваться на экзамене. У меня есть следующие модели и контроллеры, которые связаны с тем:Как отправить params при использовании данных из других моделей, чтобы заполнить форму в Rails

Тема имеет следующие столбцы:

t.string "name" 
t.integer "ects" 
t.integer "year" 
t.integer "professor_id" 

Его отношения с экзамена: has_one: экзаменационные Его отношения с профессором:
belongs_to: профессор

профессор имеет следующие столбцы:

t.string "first_name" 
t.string "last_name" 
t.string "title" 

Его отношения с экзаменом: has_many: экзамены Его отношения с темой: has_many: предметы

экзамен имеет следующие столбцы:

t.date "start_date" 
t.string "department" 
t.integer "professor_id" 
t.integer "subject_id" 

Его отношения с предмета: belongs_to: Тема Его отношения с профессором: BELONGS_TO: профессор Его отношения с Signup:

has_many :signups 
has_many :signupers, through: :signups, class_name: 'User' 

Регистрация имеет следующие столбцы:

t.integer "exam_id" 
t.integer "user_id" 

Его отношения с экзаменом: belongs_to: экзамен Его отношения с пользователем: belongs_to: пользователь

Я уже подключили все и сделал кнопку Регистрация на экзамен шоу зрения, который связан с new_signup_path. Дата начала экзамена, имя субъекта и профессор появляются в форме, когда пользователь перенаправляется на него. Таким образом, пользователь должен нажать кнопку «Отправить» только.

Это форма:

<%= form_for @signup do |f| %> 
     <%= f.fields_for :exam do |e| %> 
     <%= e.fields_for :subject do |s| %> 
      <%= s.label :name, "Subject" %> 
      <%= s.select :name do %> 
      <% [[@exam.subject.name]].each do |c| %> 
       <%= content_tag(:option, c.first, value: c.last) %> 
      <% end %> 
      <% end %> 
     <% end %> 
     <%= e.fields_for :professor do |p| %> 
      <%= p.label :professor, "Professor" %> 
      <%= p.select :first_name, :last_name do %> 
       <% [[@exam.professor.first_name + " " + @exam.professor.last_name]].each do |c| %> 
       <%= content_tag(:option, c.first, value: c.last) %> 
      <% end %> 
      <% end %> 
     <% end %> 
     <%= e.label :start_date %> 
     <%= e.date_field :start_date, value: @exam.start_date %> 
     <% end %> 
     <%= f.submit "Submit", class: "btn btn-medium btn-primary col-md-3" %> 
    <% end %> 

Все необходимые данные отображаются в форме, но когда я отправить форму он говорит, что субъект в @ exam.subject.name не определен. Тогда я понял, что мне также нужно разрешить этот параметр, а также имя профессора. Поэтому я поместил его в signup_params в контроллере регистрации и определил его в новом действии, но проблема в том, что он его не распознает (неопределенный метод `subject 'для nil: NilClass).

Вот та часть контроллера (я также попробовал некоторые другие варианты, но это не сработало Это только последняя из них.):

def new 
    @signup = Signup.new 
    @exam = Exam.find(params[:exam_id]) 
    @exam.subject = Subject.find(params[:subject_id]) 
    @exam.professor = Professor.find(params[:professor_id]) 
    end 

    def create 
    @signup = Signup.new(signup_paramas) 
    @signup.user_id = current_user.id 
    if @signup.save 
     flash[:success] = "You signed up for the exam." 
     redirect_to @signups 
    else 
     render :new 
    end 
    end 

    private 

    def signup_paramas 
    params.permit(:exam_id, :user_id).merge(subject_id: @exam.subject.id, professor_id: @exam.professor.id) 
    end 

Основная проблема заключается в том, что я не» t знать, как передать тему и параметры профессора, чтобы быть узнаваемым.

Я ценю любую помощь. Спасибо заранее

PS: Я также положил accepts_nested_attributes_for в модель экзамена.

+1

Причина этого заключается в том, что перед нажатием кнопки отправки '@ exam' является' nil', который является таким же, как 'null' в Java/C#/etc, в вашей форме вы пытаетесь получить' subject' поле, когда вы видите «неопределенный метод для nil: NilClass», помните об ошибке NullPointerException в Java/C#/etc. – niceman

+0

Я боролся с этим через весь проект. Я смог решить что-то. в некоторых случаях. – Aida

ответ

1

Проблема заключается не в параметрах регистрации. У вас есть @ exam.subject и @ exam.professor, которые не являются переменными экземпляра. Поэтому они не будут видны в представлении. Поэтому переместите это на что-то подобное.

def new 
    @signup = Signup.new 
    @exam = Exam.find(params[:exam_id]) 
    @subject = @exam.subjects.find(params[:subject_id]) 
    @professor = @exam.professors.find(params[:professor_id]) 
end 

И ваш взгляд изменения @ exam.subject в @subject и @ exam.professor к @professor.

Также, насколько я вижу, это будет делать для параметров регистрации. Поскольку вы не используете subject_id или Professor_id, я думаю, что это было бы необязательно.

def signup_paramas 
    params.permit(:exam_id, :user_id) 
end 
+0

Я попытался определить ** @ subject ** и ** @ Professor ** раньше и поместить его в представление без ** @ экзамена **, но я не знал, как это сделать должным образом. Когда я нажимаю кнопку регистрации (с помощью этого кода), он говорит: неопределенные предметы метода для экзамена. – Aida

+0

Похоже, что отношения не определены. У вас есть у профессора.rb has_many: exams и has_many: subject? –

+0

@TomConnolly У меня есть эти отношения. exam.rb (принадлежит_от: профессор, принадлежит_to: subject, has_many: регистрация). subject.rb (принадлежит: профессор, has_one: экзамен) и signup.rb (принадлежит к: пользователь, принадлежит к экзамену). – Aida

1

Сначала вы используете select форму помощника в неправильном направлении, это:

<%= s.select :name do %> 
<% [[@exam.subject.name]].each do |c| %> 
    <%= content_tag(:option, c.first, value: c.last) %> 
<% end %> 
<% end %> 

Будет только один вариант визуализации (отборный список только с одним параметром !!!), это потому, что коллекция имеет только один элемент.

Во-вторых, предоставленная опция будет иметь текст и атрибут value, равный тому же значению, например <option value="john" selected>john</option>, который в зависимости от ваших требований является правильным или неправильным.

Чтобы исправить первый выпуск коллекции должна иметь более чем один элемент, а для второго вопроса вы либо оставить его как есть или использовать коллекцию как этот [["john",1],["Mia",2]], результат этой коллекции этот HTML код:

<option value="john" selected>1</option> 
<option value="Mia">2</option> 

Второе использование select (p.select для профессоры) еще более странно, вы не можешь выбрать два атрибута в то же время, если вы хотели, чтобы обеспечить один вход для каждого атрибута необходимо поставить два p.select блоков, если вы хотите выбрать «full_name», я думаю, вы должны это сделать:

<%=p.select :full_name do%> 
    ... 
<% end %> 

И в Professor классе определяют full_name и full_name= вроде этого:

def full_name 
    first_name + " " + last_name 
end 
def full_name=(name) 
    first_name,last_name = name.split(" ") 
end 

Теперь к реальной проблеме, я думаю, что проблема заключается в новом действии здесь:

def new 
    @signup = Signup.new 
    @exam = Exam.find(params[:exam_id]) 
    @exam.subject = Subject.find(params[:subject_id]) 
    @exam.professor = Professor.find(params[:professor_id]) 
end 

Новое действие по соглашению обрабатывает Get запросы для форм, которые хотят создавать новые ресурсы, запрос Post осуществляется по соглашению с действием create, @signup настроен правильно, но другие пытаются запросить базу данных для идентификатора, исходящего от params, каковы параметры для запроса Get?

Он содержит Счетчики запросов, так что если URL-адрес для создания Регистрации является «http://example.com/signup/new», то это должно быть, как это «http://example.com/signup/new?exam_id=1&subject_id=2&professor_id=4» для params[:exam_id] и других должны быть заполнен или иначе они вернутся nil и Exam.find(nil) возвращает nil в вашем случае Полагаю, я думаю, что это проблема (я догадался, что вы не ставите какие-либо параметры запроса).

Исправление просто, новое действие должно быть так:

def new 
    @signup = Signup.new 
    @exam=Exam.new 
    @exam.subject= Subject.new 
    @exam.professor = Professor.new 
end 

Таким образом, объекты устанавливаются в пустое состояние, так что они заполняются по форме.

Теперь, когда пользователь нажимает на кнопку отправки, по соглашению create действия обрабатывает этот запрос POST, но конечно, мы должны заботиться о сильных параметрах, ваш signup_params должен быть так:

def signup_params 
    params.require(:signup).permit({:exam => [{:subject => [:name]}, 
               {:professor => [:full_name]}, 
               :start_date]}) 
end 

Это как мы разрешаем вложенные параметры в Rails, для каждого «объекта» мы помещаем хэш с одним ключом, имя ключа зависит от того, что вы передаете для fields_for, значение представляет собой массив, содержащий атрибуты, которые заполняют этот «объект», теперь, если некоторые из эти атрибуты сами являются «объектами», мы повторяем шаблон, в нашем примере у нас есть fields_for :exam, поэтому мы помещаем {:exam =>[exam_attributes]}, и поскольку экзамен единственное во всей форме нам нужно только заполнить «exam_attributes», если по случайности был, например, «@ signup.date» То, что мы хотим принять, мы сказали бы так:

params.require(:signup).permit({:exam=>[exam_attributes]},:date) 

сейчас «exam_attributes» - это «субъект», «профессор» и «start_date». «start_date» - это простое поле, но остальные объекты, поэтому мы повторяем шаблон и ... у вас есть идея.

Кстати, вы забыли .require(:signup), без этого ваше действие create может принимать запросы, которые не предоставляют signup объект, который вы не хотите.

Надеюсь, что это решает вашу проблему и счастливое кодирование Rails.

+0

Я хочу, чтобы автоматически заполнить форму, и когда я помещаю новое вместо поиска, форма пуста. У меня была params.require (: signup) в моей последней версии, но моя главная проблема заключалась в том, что я не знал, как передать дополнительные параметры для темы и профессора. Спасибо, что разъяснил это мне. Я знаю, что select используется для большего количества опций, и у меня есть только один, но я думал, что он выглядит лучше, чем text_field. Я пытаюсь получить доступ (как получить доступ к атрибутам из других моделей и контроллеров) во всем процессе создания этого приложения. Эта форма - мой последний шаг. – Aida

+0

@Aida новое действие должно оставаться таким же, как в этом ответе, то, что вы ищете, - это ошибки проверки, сохраняющие данные формы, которые имеют другой способ сделать это, я пойду проверю и вернусь к вам – niceman

+0

Моя форма заполняется, когда я отправил params.require (: signup) .permit (exam_id, user_id) и когда у меня был @exam = Exam.find (params [: exam_id]), так как он знал, к какому экзамену я обращаюсь, но была проблема с потому что он не знал, что я посылаю с предметом и профессором. – Aida