【问题标题】:struggling to understand how models and associations are saved in rails努力理解模型和关联是如何保存在 Rails 中的
【发布时间】:2012-10-16 10:39:30
【问题描述】:

我是 ruby​​ 和 rails 的新手,我希望尽可能地遵循编码标准和约定,所以我不会养成任何坏习惯。我有两个模型:课程和位置。一门课程属于一个位置,因为一门课程只能有一个位置。一个位置有_many 个课程,因为一个位置可以由多个课程共享。

创建课程时,通过其 ID 找到的位置可能已经存在。或者该位置可能还不存在,在这种情况下,必须创建一个新的位置记录。我的课程控制器具有以下创建操作。

def create
  @course = Course.new(params[:course])

  if params[:course][:location][:id].blank?
    @course.location = Location.create(params[:course][:location])
  else
    @course.location = Location.find_by_id(params[:course][:location][:id])
  end

  @course.save

  respond_with @course
end

请注意,这是一个仅使用 JSON 响应的 REST API。发出请求的 javascript 以与 GET 请求返回的格式相同的格式发布 JSON 数组

{
  "course":
  {
    "title":"US History",
    "credits":"3",
    "max_students":"100",
    "location":
    {
      "id":"",
      "building":"Freedom Hall",
      "room":"301"
    }
  }
}

or

{
  "course":
  {
    "title":"US History",
    "credits":"3",
    "max_students":"100",
    "location":
    {
      "id":"12", # this is the only difference
      "building":"Freedom Hall",
      "room":"301"
    }
  }
}
  1. 与我读过的所有示例相比,这段代码看起来并不那么优雅。有没有更好的方法来考虑它?
  2. 如果 Location.create 引发异常,是否仍会调用 @course.save?我需要使用 Location.create! 吗?
  3. 同样,验证错误是否会出现在 @course.errors 中,即使错误出现在 Location 模型上?我是否需要从异常中解救,以便将错误返回给客户端?

非常感谢您的任何帮助!

【问题讨论】:

    标签: ruby-on-rails ruby json validation associations


    【解决方案1】:

    您可以使用find_or_initialize_by_id 清除它。这应该有效:

    def create
      @course = Course.new(params[:course])
      @course.location = Location.find_or_initialize_by_id(params[:course][:location][:id],
                                                           params[:course][:location])
      @course.save
      respond_with @course
    end
    

    关于您的第二个问题,如果Location.create(或Location.find)引发异常(因为它们会首先发生),则不会在您的代码中调用@course.save。但是,按照我上面的编码方式,异常会在代码中的同一点发生,当调用save 时,关联也会被保存。

    【讨论】:

    • 谢谢!我正倾向于这样的事情,但我的脚很冷。你证实了我对异常处理的怀疑——我只是不知道幕后是否发生了任何可能影响我期望的事情。这是否需要将accepts_nested_attributes_for :location 添加到我的课程模型中?
    • 不客气。没有 AFAIK,您不必添加 accepts_nested_attributes_for :location 来执行此操作,因为您明确设置了该位置的属性。虽然,如果你有嵌套属性,我相信你可以只用@course = Course.new(params[:course]) 来初始化所有东西,location 属性会自动设置。虽然还没有测试过,所以不确定在设置位置 id 时它是否会起作用。
    • 我需要编写一些测试,但是一旦我这样做了,我会在我的发现中添加评论。我担心的是,如果在嵌套位置设置了 id,但所有其他字段为空,那么 rails 实际上会更新匹配位置上的属性,将它们设置为空(假设空字段有效),并保存记录。这将导致清除位置记录中的数据。但我不禁认为rails足够聪明,知道该怎么做。就像我说的,一旦我知道它是如何工作的,我会再次回复。
    • 如果设置了id 并且缺少其他字段,它们将不会被覆盖。但是,如果它们是空白(例如"building":""),那么是的,它们将被覆盖,但这是预期的行为,如果您不想覆盖某些内容,请不要包含它。跨度>
    【解决方案2】:

    在你的控制器中试试这个

    def new
      @course = Course.new 
      @location = @course.location.build # if one..many relationship
      @location = @course.build_location # if one..one relationship
    end
    
    def create
     @course = Course.new(params[:course])
     if @course.save
       respond_with @course
     else
       render :action => "new"
     end
    end
    

    更多关于nested_attributes

    【讨论】:

    • 感谢您的回复!与使用 find_or_initialize_by_id 相比,这样做有什么好处?我需要了解有关嵌套模型的更多信息。我想我没有将这些点与嵌套有关。
    猜你喜欢
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多