Различия между Rails 'has_one и has_many, когда дело доходит до автоматического построения данных - PullRequest
2 голосов
/ 18 января 2012

Привет, сообщество StackOverflow!

Последние несколько дней я изучаю Rails и расширяю базовый пример блога в официальном руководстве по Rails.Я хотел узнать больше о соединениях «один к одному», так как я планирую расширить систему входа в систему Devise с помощью пользовательской таблицы пользовательских данных, а правила нормализации требуют, чтобы я создал другую таблицу для фактических данных аутентификации (устройствоuser table) и еще один для пользовательской информации о приложении (моя собственная таблица пользователей).

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

Когда пользователь желает создать НОВОЕ сообщение, у контроллера есть вызов @post = Post.newкоторый готовит пустое сообщение для редактирования и создания.Также необходимо вызвать post.tags.build, чтобы убедиться, что хотя бы один тег baby, который будет принадлежать сообщению, готов для редактирования 5.times do @post.tags.build end, например, подготовит не один, а пять тегов для редактирования.

В методе create контроллера достаточно создать новую запись из params[:post] и @post.save it.Он автоматически сохраняет теги без необходимости в дополнительных вызовах функций.

Здесь я начал расширяться.Я просто хотел добавить еще одну таблицу, названную post_data, которая была бы привязана один к одному с исходной таблицей сообщений.post_data содержит внешний ключ к сообщению, которому он принадлежит, а также инструкцию belongs_to :post в его модели.Пост has_one :post_data.Это также accepts_nested_attibutes_for :post_data.

Опять же, в новом методе пост-контроллера, post_data необходимо инициализировать. @post.build_post_data делает именно это.Форма отлично отображает две разные модели - одну как post [title] ... и т. Д., А другую как post_data [data_field_name_here].

Однако в имени создания запись post_data должна быть вручную сохранено: @post.create_post_data(params[:post_data]) для того, чтобы его можно было ввести в БД.В противном случае он просто не будет сохранен.

Теперь мой вопрос таков: почему объекты has_many поста, теги просто необходимо подготовить в новом методе контроллера, а затем сохранить в createавтоматически, в то время как ссылки на has_one также необходимо сохранять вручную?

Я просто хочу узнать, почему Rails будет работать так.

Заранее спасибо за ваше время и терпение!:)

Редактировать: файлы кодов!

posts_controller

class PostsController < ApplicationController
# GET /posts
# GET /posts.json
def index
  @posts = Post.all

  respond_to do |format|
    format.html # index.html.erb
    format.json { render :json => @posts }
  end
end

# GET /posts/1
# GET /posts/1.json
def show
  @post = Post.find(params[:id])

  respond_to do |format|
    format.html # show.html.erb
    format.json { render :json => @post }
  end
end

# GET /posts/new
# GET /posts/new.json
def new
  @post = Post.new
  @post.build_post_data
  5.times do @post.tags.build end
end

# GET /posts/1/edit
def edit
  @post = Post.find(params[:id])
end

# POST /posts
# POST /posts.json
def create
  # This works now - it creates all the needed resources automatically
  @post = Post.new(params[:post])

  respond_to do |format|
    if @post.save
      format.html { redirect_to @post, :notice => 'Post was successfully created.' }
    else
      format.html { render :action => "new" }
    end
  end
end

# PUT /posts/1
# PUT /posts/1.json
def update
  @post = Post.find(params[:id])

  respond_to do |format|
    if @post.update_attributes(params[:post])
      format.html { redirect_to @post, :notice => 'Post was successfully updated.' }
    else
      format.html { render :action => "edit" }
    end
  end
end

# DELETE /posts/1
# DELETE /posts/1.json
def destroy
  @post = Post.find(params[:id])
  @post.destroy

  respond_to do |format|
    format.html { redirect_to posts_url }
  end
end
end

posts / _form.html.erb

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

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

  <div class="field">
    <%= post_form.label :name %><br />
    <%= post_form.text_field :name %>
  </div>


<%= post_form.fields_for(:post_data) do |pdf|  %>
  <div class="field">
    <%= pdf.label :herp, "DERP POST DATA" %><br />
    <%= pdf.text_field :herp %>
  </div>
<% end %>

  <div class="field">
    <%= post_form.label :title %><br />
    <%= post_form.text_field :title %>
  </div>
  <div class="field">
    <%= post_form.label :content %><br />
    <%= post_form.text_area :content %>
  </div>

<h2>Tags</h2>
<%= render :partial => 'tags/form', 
          # send some custom variables to the
          # rendered partial's context
           :locals => { :form => post_form } %>

  <div class="actions">
    <%= post_form.submit %>
  </div>
<% end %>

и сообщений.rb model

class Post < ActiveRecord::Base
  validates :name, :presence => true
  validates :title, :presence => true, :length => { :minimum => 5 }

  has_many :comments, :dependent => :destroy

  attr_accessible :post_data_attributes, :name, :title, :content

  #let's just assume this makes sense, k?
  has_one :post_data
  accepts_nested_attributes_for :post_data

  # TAGS
  has_many :tags
  accepts_nested_attributes_for :tags, :allow_destroy => :true,
    # reject if all attributes are blank
         :reject_if => lambda { |attrs| attrs.all? { |k, v| v.blank? } }
end

Окончательное редактирование:

Исправлен весь код, синхронизирован с моим рабочим кодом!: D Если кто-то из далекого будущего все еще имеет эту проблему, и мой код не работает, отправьте мне личное сообщение, и мы разберемся с ним!:)

1 Ответ

2 голосов
/ 20 января 2012

Я верю этому:

<%= fields_for(:post_data) do |pdf|  %>

Должно быть так:

<%= post.fields_for(:post_data) do |pdf|  %>

Ты можешь попробовать это?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...