Не могу создать новую модель в Rails

tl;dr: кажется, что params[:commit] не содержит актуальной информации для создания нового коммита, вместо этого он содержит только значение кнопки отправки для формы, имя которой также "commit". Любые идеи относительно того, почему это происходит? Я ничего не менял.

Я запускаю rails 3 с сервером webrick, так как он отображает соответствующую отладочную информацию. Я создал модель только с одним атрибутом, description:text, и все работает нормально.

Однако, когда я иду создавать новый, используя автоматически сгенерированную форму лесов, похоже, его не волнует значение текстовой области описания. Другими словами, после создания столбец created_at в порядке, а все, кроме description, вообще не отображаются. Вот вывод с сервера:

Started POST "/commits" for 127.0.0.1 at 2010-11-03 17:24:20 -0700
Processing by CommitsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"F00A8Ttv7ceREegfZmP+T5kr+6u2YbRJrQzmfEOaT7o=", "commit"=>"Create Commit"}
SQL (0.5ms)  INSERT INTO "commits" ("created_at", "description", "updated_at") VALUES ('2010-11-04 00:24:20.986571', NULL, '2010-11-04 00:24:20.986571')
Redirected to http://0.0.0.0:3000/commits/5
Completed 302 Found in 42ms

Вот как выглядит моя миграция, автоматически сгенерированная rails generate

def self.up
  create_table :commits do |t|
    t.text :description

    t.timestamps
  end
end

Итак, как вы можете видеть, он видит значение описания как NULL, хотя я что-то ввел в текстовую область. Вот какие рельсы сгенерированы в партиале _form.html.erb:

<div class="field">
  <%= f.label :description %><br />
  <%= f.text_area :description %>
</div>

У кого-нибудь есть идеи, почему это происходит? Я почти уверен, что это тоже очевидная вещь.

Кстати, rails console отлично работает, когда я создаю его и сохраняю вручную, поэтому у меня такое ощущение, что в контроллере происходит отключение, когда он переходит к сохранению или что-то в этом роде.

EDIT: я заметил кое-что интересное. В контроллере объект создается как таковой:

@commit = Commit.new(params[:commit])

Однако, как отмечено в выходных данных webrick выше, сервер получает только следующие параметры:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"F00A8Ttv7ceREegfZmP+T5kr+6u2YbRJrQzmfEOaT7o=", "commit"=>"Create Commit"}

Таким образом, не похоже, что он получает параметр description, который, как я полагаю, должен был быть заключен в параметр commit, но затем, если я посмотрю на источник формы new, он покажет, что текстовая область описания имеет имя commit[description], но кнопка отправки имеет имя commit. Так что каким-то образом он получает только значение кнопки отправки, которая действительно имеет значение «Создать фиксацию», а не другую требуемую информацию.

Я не так много знаю о рельсах, поэтому я действительно не знаю, так ли это или что.

Кто-нибудь, пожалуйста, помогите мне, ха-ха.

EDIT: вот остальная часть партиала _form.html.erb, сгенерированного rails. Возможно, вы заметите вопиющую проблему:

<%= form_for(@commit) do |f| %>
  <% if @commit.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@commit.errors.count, "error") %> prohibited this commit from being saved:</h2>

      <ul>
      <% @commit.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :description %><br />
    <%= f.text_area :description %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Ответ: кажется, что Rails 3 теперь автоматически присваивает каждой кнопке отправки имя "commit", которое конфликтует с названием моей модели. Я так же боялся. Мне интересно, есть ли какие-либо дальнейшие последствия использования этого имени. Эта проблема была решена путем явного изменения вызова submit на:

f.submit "Button Text", :name => "something_else"

person Jorge Israel Peña    schedule 04.11.2010    source источник
comment
Можете ли вы включить остальную часть вашей формы, пожалуйста.   -  person mark    schedule 04.11.2010
comment
@mark: конечно, я просто не думал, что это будет актуально, поскольку это именно то, что рельсы всегда генерируют. Но я его сейчас вставлю :)   -  person Jorge Israel Peña    schedule 04.11.2010
comment
Выглядит нормально. Единственное, что я могу предположить, это коммит, который является вероятным кандидатом на зарезервированное слово, может быть, новое в рельсах 3?   -  person mark    schedule 04.11.2010
comment
@mark: после дальнейшего расследования вы правы. В Rails 3 кнопкам отправки автоматически присваивается имя фиксации.   -  person Jorge Israel Peña    schedule 04.11.2010


Ответы (2)


По умолчанию строительные леса rails создадут форму, которая будет выглядеть примерно так:

<%= form_for @commit do |f| %>
  <%= f.label :description %>
  <%= f.text_area :description %>
  <%= submit_tag "Create" %>
<% end %>

Обратите внимание, что я свернул содержимое партиала в саму форму. Важно понимать, какой HTML генерируется, когда это происходит. Это будет выглядеть так:

<form action="/commits/create" method="post">
  <label for="commit_description">Description:</label>
  <textarea id="commit_description" name="commit[description]"></textarea>
  <input name="commit" type="submit" value="Create" />
</form>

Проблема, с которой вы столкнулись, — это конфликт имен между именем кнопки отправки и именем объекта. Обычно, когда рельсы встречают имя формы, такое как «commit[description]», он сохраняет результаты в @params, поэтому значение выглядит следующим образом:

@params[:commit] = { :description => 'value' }

Собственно, это и сделали рельсы. Проблема заключалась в том, что имя по умолчанию, сгенерированное помощником формы «submit_tag», также называется «commit». Поэтому, когда рельсы столкнулись с этим параметром формы, он перезаписал результаты формы следующим образом:

@params[:commit] = "Create" # same name as the value of the submit button

Чтобы обойти эту коллизию имен, у вас есть несколько вариантов. Первый вариант — вручную написать кнопку отправки на простом старом HTML. Конечно, вы потеряете некоторые параметры, но, по крайней мере, вы можете изменить имя кнопки отправки на что-то другое:

<input type="submit" name="who_cares" value="Create Commit" />

Другой вариант — использовать вариант помощника form_for. В этом случае строка открытия формы будет выглядеть так:

<%= form_for :newcommit, @commit, :url => { :action => "create" } do |f| %>
  <%= f.label :description %>
  <%= f.text_area :description %>
  <%= submit_tag "Create" %>
<% end %>

Это изменит результирующий HTML-код, чтобы он выглядел следующим образом:

<form action="/commits/create" method="post">
  <label for="newcommit_description">Description:</label>
  <textarea id="newcommit_description" name="newcommit[description]"></textarea>
  <input name="commit" type="submit" value="Create" />
</form>

Это привяжет данные вашей формы к параметру @params[:newcommit], и вы сможете продолжить обработку в обычном режиме.

Для вашего дальнейшего удовольствия от чтения:

http://guides.rubyonrails.org/form_helpers.html

person Berin Loritsch    schedule 04.11.2010
comment
Спасибо, Берин, это очень информативный ответ. Я просто хочу спросить тебя об одном. Я понимаю ваши решения, они имеют смысл, но могу ли я просто сделать то, что рекомендовал PeterWong, изменить имя тега отправки? В конце концов, я так понимаю, что это столкновение произойдет только в форме создания модели фиксации, верно? В любом случае, я приму ваш ответ, так как он более информативен, но я был бы признателен за ответ. - person Jorge Israel Peña; 04.11.2010
comment
Это верно. Основным виновником является конфликт имен, поэтому вам нужно изменить имя отправки или имя, используемое для вашего объекта. - person Berin Loritsch; 04.11.2010

form_for генерирует поля с именем вроде commit[description]. Однако последняя подбитовая кнопка имеет имя commit. Я думаю, что последняя кнопка отправки перезаписывает передние commit[]s.

Так что попробуйте <%= f.submit "Your button text", :name => "something_else" %>

person PeterWong    schedule 04.11.2010
comment
Спасибо. После дальнейшего изучения кажется, что Rails 3 автоматически присваивает каждой кнопке отправки имя фиксации, которое конфликтует с именем моей модели. Это исправляет это. Однако меня беспокоит, не столкнусь ли я с чем-то подобным позже, если оставлю это имя для модели. - person Jorge Israel Peña; 04.11.2010
comment
Да, даже для submit_tag автоматически добавляется имя commit. Поэтому вам лучше переименовать свою модель или перезаписать имя кнопки, или использовать настраиваемый построитель форм, который автоматически перезаписывает имя кнопки отправки. - person PeterWong; 04.11.2010