【问题标题】:Creating model relationships/Nested resourses创建模型关系/嵌套资源
【发布时间】:2016-10-18 22:31:10
【问题描述】:

您好,我正在尝试在我添加的两个模型 Establishments 和 OpenClosed 之间建立关系

class Establishment < ApplicationRecord
  has_many :open_closed
end

class OpenClosed < ApplicationRecord
  belongs_to :establishment
end

我在 open_closed 表中添加了建立 ID 字段,然后运行 ​​rails db:migrate。接下来我嵌套了资源

resources :establishments do
  resources :open_closeds
end 

然后我修改了 OpenClosed 控制器 #new 行注释,其中我添加了新代码

def new
 @establishment = Establishment.find(params[:establishment_id]) #new line added
 @open_closed = OpenClosed.new
end

 # GET /open_closeds/1/edit
def edit
end

# POST /open_closeds
# POST /open_closeds.json
def create
 @establishment = Establishment.find(params[:establishment_id]) #new line added
 @open_closed = OpenClosed.new(open_closed_params)
 @open_closed.Establishment = @establishments #new line added

respond_to do |format|
  if @open_closed.save
    format.html { redirect_to @open_closed, notice: 'Open closed was       successfully created.' }
    format.json { render :show, status: :created, location: @open_closed }
  else
    format.html { render :new }
    format.json { render json: @open_closed.errors, status: :unprocessable_entity }
  end
 end
end

这是我在 open_closed 视图中提交表单时遇到的错误:

undefined method `Establishment=' for # 你的意思是?建立=建立建立ID=建立ID建立ID?

我这辈子都无法解决我在哪里出错了,请有人为我指出正确的方向,非常感谢。

【问题讨论】:

  • 什么是 OpenClosed?你的意思是像business hours这样的东西吗?

标签: ruby-on-rails nested-resources


【解决方案1】:

首先,将OpenClosed#new 操作重写为如下所示:

<h1>New Open Closed</h1>

<%= render 'form', establishment: @establishment, open_closed: @open_closed %>
<%= link_to 'Back', establishment_open_closeds_path %>

这意味着我们现在将一个Establishment 对象和一个OpenClosed 对象传递给表单部分。

接下来,将&lt;%= form_for ... %&gt; 声明更改为

`app/views/open_closeds/_form.html.erb`

看起来像这样:

<%= form_for [establishment, open_closed] do |f| %>

我们刚刚告诉我们的表单使用Establishment 和OpenClosed 对象。

接下来,重写 open_closed 控制器,如下所示:

def create
  @establishment = Establishment.find(params[:establishment_id])
  @open_closed = OpenClosed.new(open_closed_params)
  @open_closed.Establishment = @establishment #new line added

  respond_to do |format|
    if @open_closed.save
      format.html { redirect_to [@establishment, @open_closed], notice: 'Open closed was successfully created.' }
      format.json { render :show, status: :created, location: @open_closed }
    else
      format.html { render :new }
      format.json { render json: @open_closed.errors, status: :unprocessable_entity }
    end
  end
end

我做了两个修改:

换行

@open_closed.Establishment = @establishments

到

@open_closed.establishment = @establishment

请注意,建立中的“e”现在是小写的,我删除了行尾的“s”(这可能只是一个错字)。如果您查看您的 db/schema.rb 文件,您应该会看到

t.integer  "establishment_id"

在open_closeds 表下。在 ActiveRecord 中,您可以使用与数据库表中的行相同的名称访问类的方法。然而,对于像establishment_id 这样的外键,rails 足够聪明,知道当你说@open_closed.establishment 时,你真的只想要属于你的OpenClosed 对象的Establishment。

我在上面的代码中改变的第二件事是这一行:

redirect_to [@establishment, @open_closed] ...    

您需要同时提供establishment 和open_closed 对象才能使路由有效。由于重定向语句将您发送到 OpenClosed 类的 show 方法,您可以运行 rake routes 以查看 OpenClosed#show 的路由是什么样的。我在你的路由文件上运行了rake routes,并为 OpenClosed 的 show 方法得到了这个

establishment_open_closed GET    /establishments/:establishment_id/open_closeds/:id(.:format)      open_closeds#show

所以你可以看到OpenClosed#show 期望一个Establishment 对象和一个OpenClosed 对象。您只需将数组中的两个对象作为第一个参数提供给redirect_to

注意:

您在尝试此操作时可能仍然会收到错误,因为应用程序中的许多路由不正确并且需要更改。例如,要实际渲染OpenClosed#show 视图(这是在成功调用OpenClosed#create 后重定向到的位置),您需要对 OpenClosed 控制器的显示模板进行以下修改:

<p id="notice"><%= notice %></p>

<%= link_to 'Edit', edit_establishment_open_closed_path(@open_closed) %> |
<%= link_to 'Back', establishment_open_closeds_path %>

作为对未来的提示,您可以添加

&lt;%= debug(params) if Rails.env.development? %&gt; 在你的 app/views/layouts/application.html.erb 文件中直接在 yield 之后。这将打印出在调试时有用的服务器响应信息。

最后,在您修复路线之前,您的应用程序的其他部分将无法工作,但希望您现在有足够的信息来执行此操作。

有关嵌套路由的更多信息,请查看official rails guids

编码愉快!

【讨论】:

  • 感谢您提供的非常翔实的回答,它真的让我理解了很多,在花了几个小时整理我的路线后,感谢您的建议,我让它工作了。不错的小学习曲线干杯。
  • 太棒了!很高兴我能帮忙:)
【解决方案2】:

您需要像这样更改您的代码:

@open_closed = @establishment.open_closeds.new(open_closed_params)

所以它会为你分配@open_closed.establishment_id。

您似乎还需要将has_many :open_closed 更改为has_many :open_closeds。

【讨论】:

    【解决方案3】:
    @open_closed.Establishment = @establishments #new line added
    

    这是失败的行。 那应该是:

    @open_closed.establishment = @establishment #new line added
    

    请注意,大小写非常重要。您的关联对象永远不会以大写字母开头 - 大写字母用于类名(例如,当您定义建立模型时)或常量(您在这里没有使用)。

    还要注意你有一个错字 -> @establishment 不是复数(只有一个):)

    【讨论】:

    • 类名是常量
    • 但与 ALL_SHOUTY_CONSTANTS 不同 :) 它们属于自己的一类(呵呵)
    • Ruby 不区分 ALLCAPS 和 CamelCase - 只要它以大写字母开头,它就是一个常量。 class Foo; end 实际上只是 Foo = Class.new 的语法糖。您可以声明您的课程LIKE_BACK_WHEN_FORTRAN_WAS_THE_BEES_KNEES = Class.new,但这可能会导致焦油和羽化以及水冷却器后面的肥皂敲打。
    • 是的,Ruby 确实是这样工作的,但是对于初学者 Rails 开发人员来说——区别真的不重要,他们最好知道类以单个大写开头,而它们不是与 ALLCAPS 常量完全相同……这对于记忆标准 Rails 实践更好。如果您真的想打破标准的 Rails 命名/大写惯例,那么它们可能被以相同的方式对待的细节真的并不重要。
    猜你喜欢
    • 2016-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    相关资源
    最近更新 更多