Rails第二级嵌套资源

时间:2014-08-26 07:59:49

标签: ruby-on-rails routing resources nested

我在显示资源字段的任何视图时遇到问题。我有这种关联:用户有一个农场,农场有很多领域。

我的模特:

User.rb
has_one :farm

devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable, 
     :token_authenticatable, :confirmable, :lockable, :timeoutable


attr_accessible :email, :password, :password_confirmation, :remember_me, :username

--
Farm.rb
belongs_to :user
has_many :fields

attr_accessible :name, :contact, :adress, :user_id


--
Field.rb

belongs_to :farm


attr_accessible :crop, :longitude, :latitude, :occupied, :farm_id

我的佣金路线:

    user_farm_fields GET /users/:user_id/farm/:farm_id/fields(.:format)
    {:action=>"index", :controller=>"fields"}
            POST   /users/:user_id/farm/:farm_id/fields(.:format)
    {:action=>"create", :controller=>"fields"}
    new_user_farm_field GET    /users/:user_id/farm/:farm_id/fields/new(.:format)          {:action=>"new", :controller=>"fields"}
edit_user_farm_field GET    /users/:user_id/farm/:farm_id/fields/:id/edit(.:format){:action=>"edit", :controller=>"fields"}
     user_farm_field GET    /users/:user_id/farm/:farm_id/fields/:id(.:format)      {:action=>"show", :controller=>"fields"}
                     PUT    /users/:user_id/farm/:farm_id/fields/:id(.:format)      {:action=>"update", :controller=>"fields"}
                     DELETE /users/:user_id/farm/:farm_id/fields/:id(.:format)      {:action=>"destroy", :controller=>"fields"}
          user_farms GET    /users/:user_id/farm(.:format)
    {:action=>"index", :controller=>"farms"}
                     POST   /users/:user_id/farm(.:format)
    {:action=>"create", :controller=>"farms"}
       new_user_farm GET    /users/:user_id/farm/new(.:format)
    {:action=>"new", :controller=>"farms"}
      edit_user_farm GET    /users/:user_id/farm/:id/edit(.:format)
    {:action=>"edit", :controller=>"farms"}
           user_farm GET    /users/:user_id/farm/:id(.:format)
    {:action=>"show", :controller=>"farms"}
                     PUT    /users/:user_id/farm/:id(.:format)
    {:action=>"update", :controller=>"farms"}
                     DELETE /users/:user_id/farm/:id(.:format)
    {:action=>"destroy", :controller=>"farms"}
               users GET    /users(.:format)
    {:action=>"index", :controller=>"users"}
                     POST   /users(.:format)
    {:action=>"create", :controller=>"users"}
            new_user GET    /users/new(.:format)
    {:action=>"new", :controller=>"users"}
           edit_user GET    /users/:id/edit(.:format)
    {:action=>"edit", :controller=>"users"}
                user GET    /users/:id(.:format)
    {:action=>"show", :controller=>"users"}
                     PUT    /users/:id(.:format)
    {:action=>"update", :controller=>"users"}
                     DELETE /users/:id(.:format)
    {:action=>"destroy", :controller=>"users"}
    new_user_session GET    /accounts/sign_in(.:format)
    {:action=>"new", :controller=>"devise/sessions"}
        user_session POST   /accounts/sign_in(.:format)
    {:action=>"create", :controller=>"devise/sessions"}
destroy_user_session GET    /accounts/sign_out(.:format)
    {:action=>"destroy", :controller=>"devise/sessions"}
       user_password POST   /accounts/password(.:format)
    {:action=>"create", :controller=>"devise/passwords"}
   new_user_password GET    /accounts/password/new(.:format)
    {:action=>"new", :controller=>"devise/passwords"}
  edit_user_password GET    /accounts/password/edit(.:format)
    {:action=>"edit", :controller=>"devise/passwords"}
                     PUT    /accounts/password(.:format)
    {:action=>"update", :controller=>"devise/passwords"}
   cancel_user_registration GET    /accounts/cancel(.:format)
    {:action=>"cancel", :controller=>"devise/registrations"}
   user_registration POST   /accounts(.:format)
    {:action=>"create", :controller=>"devise/registrations"}
  new_user_registration GET    /accounts/sign_up(.:format)
    {:action=>"new", :controller=>"devise/registrations"}
  edit_user_registration GET    /accounts/edit(.:format)
     {:action=>"edit", :controller=>"devise/registrations"}
                     PUT    /accounts(.:format)
    {:action=>"update", :controller=>"devise/registrations"}
                     DELETE /accounts(.:format)
    {:action=>"destroy", :controller=>"devise/registrations"}
   user_confirmation POST   /accounts/confirmation(.:format)
    {:action=>"create", :controller=>"devise/confirmations"}
  new_user_confirmation GET    /accounts/confirmation/new(.:format)
    {:action=>"new", :controller=>"devise/confirmations"}
                     GET    /accounts/confirmation(.:format)
    {:action=>"show", :controller=>"devise/confirmations"}
         user_unlock POST   /accounts/unlock(.:format)
    {:action=>"create", :controller=>"devise/unlocks"}
     new_user_unlock GET    /accounts/unlock/new(.:format)
    {:action=>"new", :controller=>"devise/unlocks"}
                     GET    /accounts/unlock(.:format)
    {:action=>"show", :controller=>"devise/unlocks"}
          home_index GET    /home/index(.:format)
    {:controller=>"home", :action=>"index"}
                root        /
    {:controller=>"home", :action=>"index"}

我的新表格形式:

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

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

<div class="field">
<%= f.label :crop %><br />
<%= f.text_field :crop %>
</div>
<div class="field">
<%= f.label :longitude %><br />
<%= f.text_field :longitude %>
</div>
<div class="field">
<%= f.label :latitude %><br />
<%= f.text_field :latitude %>
</div>
<div class="field">
<%= f.label :occupied %><br />
<%= f.check_box :occupied %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

我相应的新方法:

def new
@farm = Farm.where("user_id = ?", current_user).first
@user = current_user

@field = Field.new

respond_to do |format|
  format.html # new.html.erb
  format.json { render json: @field }
end

我的routes.rb:

resources :users do
  resources :farms, :path => 'farm' do
    resources :fields
  end
end


devise_for :users, :path => 'accounts'

在我尝试使用此链接创建新字段后:

<%= link_to 'New Field', new_user_farm_field_path(@user, @farm, @field) %>

我收到此消息:

undefined method `user_fields_path' for #<#<Class:0x496e1b0>:0x496b6d8>

1 个答案:

答案 0 :(得分:0)

在表面层面,问题可能与form_for帮助程序在没有正确嵌套结构时尝试为表单设置url有关

您可以尝试这样做:

#app/views/fields/new.html.erb
<%= form_for [@user, @farm, @field], url: user_farm_fields_path do |f| %> #-> the create path

-

<强>嵌套

可能会有一些deeper issues

  

相应的路线助手是publisher_magazine_photo_url,   要求您在所有三个级别指定对象。的确,这个   情况令人困惑,这是Jamis Buck的一篇热门文章   为好的Rails设计提出了一个经验法则:

     

资源不应该嵌套超过1级。

这里需要注意的是,文档规定你可以做你正在做的事情(深度嵌套)(我原本以为你不应该这样做)。无论如何,我认为你可能会考虑让你的路线更加“浅”,以确保它们更易于管理。

为此,我希望您考虑user在您所做的事情中的作用:

User has_one Farm

这意味着当您致电resources :farms时,您已获得antipattern - 如果用户只有一个农场,您如何选择农场?当然,更好的方法是删除对用户的任何依赖,创建singular resource for :farm,然后像以前一样设置fields

以下是我的表现:

#config/routes.rb
root "farms#index"
resources :farms, only: :index

resource :farm do #-> domain.com/farm (authentictable)
   resources :fields #-> domain.com/farm/fields/new
end

#app/controllers/farms_controller.rb
Class FarmsController < ApplicationController
    before_action :authenticate_user!, except: :index

    def show
      @farm = current_user.farm
    end

    def index
      @farms = Farm.all
    end
end

#app/models/user.rb
Class User < ActiveRecord::Base
   has_one :farm
   before_create :build_farm #-> creates farm if not already built
end

这使您能够连接到current_user

,从而恢复所有工作
#app/views/fields/new.html.erb
<%= form_for [@farm, @field] do |f| %>
  <%= f.text_area :field_name %>
  <%= f.submit %>
<% end %>

#app/controllers/fields_controller.rb
Class FieldsController < ApplicationController
  before_action :authenticate_user!

  def new
     @farm = current_user.farm
     @field = @farm.fields.new
  end

  def create
      @farm = current_user.farm
      @field = @farm.fields.new field_params
  end

  private

  def field_params
     params.require(:field).permit(:field_name)
  end
end