#<配置文件:0x00007fea78589ac0>的未定义方法'street'

时间:2019-11-26 18:59:56

标签: ruby-on-rails

我有一个拥有个人资料的用户(2个型号)。这是我的架构的相关部分:

  create_table "profiles", force: :cascade do |t|
    t.text "about"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "user_id"
  end

create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "provider"
    t.string "uid"
    t.string "first_name"
    t.string "last_name"
    t.string "street"
    t.integer "house_number"
    t.string "city"
    t.integer "zip_code"
    t.string "image"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

之所以将个人资料作为单独的模型,是因为我认为以后对某些操作分配角色更容易。因此,现在我想知道是否有可能要求

user.first_name , user.last_name, user.email and user.password 

在注册表中并用于

user.street, user.house_number, user.city and user.zip_code 

在“个人资料#new _form”中。像这样:

<%= form_for([@user, @profile], url: user_profiles_path, method: :post) do |form| %>


  <div class="field">
    <%= form.label :about %>
    <%= form.text_area :about %>
  </div>

  <div class="field">
    <%= form.file_field :avatar %>
    <% form.label "Profile photo" %>
  </div>


  <div class="field">
    <%= form.label :street %><br />
    <%= form.text_field :street, class: 'form-control' %>
  </div>


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

因此,在这里您可以看到,该头像和大约是指个人资料,而街上的用户则来自User表。但是以某种方式,这种形式并不能理解这一点。我允许将nested_attributes用于:profile,但是我猜想,对于这种形式,这无关紧要。我知道,也许更简单的方法是重新排列我的表,以便所有地址属性都存储在Profile中。但是,由于我是Rails的新手,我真的很想了解更多,我很想知道,是否有一种方法可以同时保存到@user和@profile?谢谢!

1 个答案:

答案 0 :(得分:0)

您在这里碰到两个稍有不同的概念,大多数初学者都对此感到困惑。

第一个是nested resources。嵌套资源的路径嵌套在另一个资源下。

# config/routes.rb
resources :magazines do
  resources :ads
end

所以现在有了/ads,而不是/magazines/:magazine_id/ads。因此,路由本身以RESTful方式(很棒)描述了两种资源之间的关系。

class AdsController < ApplicationController
  before_action :set_magazine

  # GET /magazines/:magazine_id/ads/new
  def new
    @ad = @magazine.ads.new
  end

  # POST /magazines/:magazine_id/ads/new
  def create
    @ad = @magazine.ads.new(ad_params)
    if @ad.save
       redirect_to @ad
    else
       render :new
    end
  end

  def set_magazine 
    @magazine = Magazine.find(params[:magazine_id])
  end
  # ...
end
<%= form_for([@ad, @magazine]) do |f| >
  # ...
<% end %>

这将使您创建属于杂志的广告。它不会神奇地让您同时以相同的形式创建杂志。

这就是nested attributes的用处。它在模型中创建了一个超级功能的设置器,它可以接受关联模型的属性,并在与父代相同的请求中创建/更新关联记录。

例如,这将使我们以相同的形式创建用户和个人资料:

class User < ApplicationRecord
  has_one :profile
  accepts_nested_attributes_for :profile
end 

class Profile < ApplicationRecord
  belongs_to :user
end
<%= form_for(@user) do |f|>
  <div class="field">
    <%= f.label :email %>
    <%= f.email_field :street, class: 'form-control' %>
  </div>
  # ...
  <%= f.fields_for(:profile) do |profile_fields| %>
    <div class="field">
      <%= profile_fields.label :about %>
      <%= profile_fields.text_area :about %>
    </div>
  <% end %>

  # ...
<% end %>
class UsersController < ApplicationRecord

  POST /users
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to :user
    else
      render :new
    end
  end

  # ...

  private
  def user_params
    params.require(:user)
          .permit(:email, ..., profile_attributes: [:about])
  end
end

accepts_nested_attributes_for是最容易被误解,误解和最难理解的概念之一。如果您只是刚入门,则应该考虑绕过此方法,并在对导轨有了更好的了解后再转一圈。