嵌入式对象的 NoMethodError(未定义方法)

NoMethodError (undefined method) for embedded object

我正在尝试保存嵌入另一个的 Mongo::Document。我的 classes:

class Block 
  include Mongoid::Document    
  field :name, type: String
  field :text, type: String
  embeds_many :replies         
end

其他class:

class Reply
    include Mongoid::Document    
    field :content_type, type: String
    field :title, type: String
    field :payload, type: String
    embedded_in :block
end

并在控制器中创建方法:

def create
        @block = Block.where(:name => block_params[:name])        
        @quick_reply = Reply.new(title: params[:block][:quick_replies][:title], payload: params[:block][:quick_replies][:payload] )
        @block.replies.push(@quick_reply)          
        @block.name = params[:block][:name]
        @block.text = params[:block][:text]      
        if (@block.save)
            respond_to do |format|
                format.html {render :template => "block/text/edit"}
            end            
        end        
    end

我收到此错误:

undefined method `replies' for #<Mongoid::Criteria:0x71cf550>

我想了解为什么以及如何解决这个问题。谢谢

@block = Block.where(:name => block_params[:name])  

.where 不会给你一条记录——而是给你一个标准(有点像 ActiveRecord::Relation),这是一个延迟加载对象,可能包含多个甚至根本没有记录.

相反,您需要使用 .find_by 来 select 一条记录:

@block = Block.find_by(name: block_params[:name])  

如果找不到块,这也会引发 Mongoid::Errors::DocumentNotFound - 这是一件好事。如果找不到该块,则尝试创建嵌套记录将毫无意义。

还有一种创建嵌套记录的更好方法 - 使用 accepts_nested_attributes_for。如果您想在单个操作中编辑文档及其子文档,这也很有用。

但您可能首先要寻找的是使回复成为嵌套资源:

# config/routes.rb
resources :blocks do
  resources :replies, only: [:new, :create]
end

class RepliesController

  before_action :set_block

  # GET /blocks/:id/replies/new
  def new
    @reply = @block.replies.new
  end

  # POST /blocks/:id/replies
  def create
    @reply = @block.replies.new(reply_params)
    if @reply.save
      redirect_to @block, success: 'Thank you for your reply'
    else
      render :new, error: 'Your reply could not be saved'
    end
  end

  private
  def set_block
    @block = Block.find(params[:id])
  end

  def reply_params
    params.require(:reply).permit(:title, :payload)
  end
end

<%= form_for([@block, @reply || @block.replies.new]) do |f| %>
  <div class="row">
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>
  <div class="row">
    <%= f.label :payload %>
    <%= f.text_field :payload %>
  </div>
  <%= f.submit %>
<% end %>