如何使用rails保护质量分配中的关联保存到数据库

尝试几个小时后,我无法保存到数据库。

上下文是这样的:我有两种类型的用户,一种用于我只需要非常基本的信息[用户名,电子邮件,密码]和另一种用户,我需要大量的信息[年龄,性别,城市等等] ]

我没有使用STI,因为表中会有大量的Null值。 所以我创建了这三种模式,其中用户具有简档(简档表)或不具有取决于其类型[1或2],并且该简档的字段是该用户所居住的城市,其与另一个表相关。数据库,城市表

class User < ActiveRecord::Base has_one :profile has_one :city, through: :profile end class Profile < ActiveRecord::Base belongs_to :user belongs_to :city [...a bunch of fields here] end class City < ActiveRecord::Base has_many :profiles has_many :users, through: :profiles end 

当我在rails控制台中玩它们时一切顺利:

 usr = User.new(name: "roxy", email: "roxy@example.me", password: "roxanna", password_confirmation: "roxanna", utype: 1) cty = City.new(name: "Bucaramanga") prf = Profile.new (rname: "Rosa Juliana Diaz del Castillo"...) prf.city = cty usr.profile = prf usr.valid? => true usr.save => true 

但是当我尝试在应用程序中保存时(查看模型)

   'Selecciona tu ciudad'}%> def new @profile = Profile.new end def create @profile = params[:profile] @city= City.find_by_id(params[:city].to_i) @profile.city = @city end 

我收到此错误:

 undefined method `city=' for # 

有人可以帮帮我吗?

更新正如David建议我在create方法的第一行创建了Profile对象,所以我的控制器现在看起来像这样:

 def create @profile = Profile.new(params[:profile]) @city= City.find_by_id(params[:city].to_i) @profile.city = @city @usr = current_user if @usr.profile.exists? @profile @usr.errors.add(:profile, "is already assigned to this user") # or something to that effect render :new else @usr.profile << @profile redirect_to root_path end end 

但我现在收到这个错误

 undefined method `exists?' for nil:NilClass 

current_user返回@current_user

 def current_user @current_user ||= User.find_by_remember_token(cookies[:remember_token]) end 

你能告诉我,我做错了什么?

我想把这个写给所有和我一样开始并且坚持这一步的人。

我不得不创建一个新项目并使用它来实现我做错了什么。 我发现我正在validation我添加到“ Profiles表中的最后一个字段并且有

 # education :string(255) not null 

但我还没有将它添加到表单中,因此启动的错误是:

 Failed to save the new associated so_profile. 

现在,您知道如果您遇到此错误,请检查您的架构并查找表单中可能缺少的NOT_NULL字段,同时您可以注释掉所有模型validation,并在其工作取消注释之后确定。

所以,我的最终模特:

 class User < ActiveRecord::Base has_one :profile has_one :city, through: :profile attr_accessible :email, :name end class Profile < ActiveRecord::Base belongs_to :user belongs_to :city attr_accessible :age, :fcolor, :gender end class City < ActiveRecord::Base has_many :profiles has_many :users, through: :profiles attr_accessible :name end 

我的控制器:

 class ProfilesController < ApplicationController def new @user = User.find_by_id(params[:id]) @profile = Profile.new end def create @profile = Profile.new(params[:profile]) city = City.find_by_id(params[:city]) @profile.city = city @user = User.find_by_id(params[:userid]) @user.profile = @profile if @user.save flash[:success] = "Guardado" redirect_to profile_path(id: @user.id) end end def show @user = User.find(params[:id]) end end class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(params[:user]) if @user.save flash[:success] = "Registrado!" redirect_to new_profile_path(id: @user.id) else flash[:error] = "No Registrado :(" redirect_to new end end def show @user = User.find_by_id(params[:id]) end end 

在真正的应用程序中,您必须使用Cookie或其他东西来保持会话活动,因此user_token来自您获取user_id的位置,但它可以与关联一起使用。

观点:

型材/ new.html.erb

 <%= @user.name %> <%= form_for @profile, url: {action: :create, userid: @user.id } do |f| %> <%= f.label :age, "Edad" %> <%= f.text_field :age%> 
<%= label :city, "Ciudad"%> <%= select_tag :city, options_from_collection_for_select(City.all, 'id', 'name')%> <%= f.submit %> <% end %>

型材/ show.html.erb

 Hello <%= @user.name %>
Tu edad es: <%= @user.profile.age %>
Vives en <%= @user.profile.city.name%>

用户/ new.html.erb

 <%= form_for @user do |f|%> <%= f.label :name, "Nombre"%> <%= f.text_field :name, size: 20, placeholder: "Escribe tu nombre aqui" %>
<%= f.label :email, "Email"%> <%= f.text_field :email, size: 20, placeholder: "Escribe tu email aqui" %>
<%= f.submit "Sign me up!"%>

用户/ show.html.erb

 Name: <%= @user.name %>
Email: <%= @user.email %>

就是这样!

干杯。

我认为正确的是

 @so_profile.City 

 @so_profile.city 

因为class级名称是城市

学习阅读错误消息。 问题是@profile是一个哈希,因为你实际上并没有在create方法的第一行创建一个新的Profile对象。