我正在尝试在Rails 4中创建一个应用程序。
我有个人资料模型,资格模型和视觉模型。
协会是:
profile.rb
has_many :qualifications
accepts_nested_attributes_for :qualification
has_one :vision
accepts_nested_attributes_for :vision
qualification.rb
belongs_to :profile
vision.rb
belongs_to :profile
我有几个其他模型在类似的构造中作为资格和愿景(即它们属于个人资料)。
所有相关属性都包含在模型的强参数中以及它们嵌套的位置,也包含在配置文件的强参数中。
def profile_params
params[:profile].permit(:user_id, :title, :hero, :overview, :research_interest, :occupation, :external_profile,
:working_languages, :tag_list,
personality_attributes: [:average_day, :fantasy_project, :preferred_style],
vision_attributes: [:long_term, :immediate_challenge],
qualifications_attributes: [:id, :level, :title, :year_earned, :institution, :_destroy] )
end
表单设置为:
<%= simple_form_for(@profile) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<div class="intpol2">
Your professional qualifications
</div>
<%= render 'qualifications/form', f: f %>
</div>
<div class="intpol2">
Your research vision
</div>
<%= render 'visions/form', f: f %>
</div>
<div class="form-actions">
<%= f.button :submit, "Submit", :class => 'formsubmit' %>
</div>
<% end %>
然后在资格表格中,我有:
<%= simple_fields_for :qualification do |f| %>
<div class="form-inputs">
<div class="row">
<div class="col-md-6">
<%= f.input :title, :label => "Your award" %>
</div>
<div class="col-md-6">
</div>
</div>
<div class="row">
<div class="col-md-6">
<%= f.input :level, collection: [ "Bachelor's degree", "Master's degree", "Ph.D", "Post Doctoral award"] %>
</div>
<div class="col-md-6">
<%= f.input :year_earned, :label => "When did you graduate?", collection: (Date.today.year - 50)..(Date.today.year) %>
</div>
</div>
</div>
<% end %>
同样,在视觉形式中,我有:
<%= simple_fields_for :vision do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :long_term, as: :text, :label => "What is your long term research vision?", :input_html => {:rows => 10} %>
<%= f.input :immediate_challenge, as: :text, :label => "What do you see as the immediate challenge to be addressed in pursuit of your long-term vision?", :input_html => {:rows => 10} %>
</div>
<% end %>
问题是,当我在个人资料表单上按提交时,这些属性不会保存。控制台显示这两个表中都没有输入。
这个过程还有另一个步骤吗?
我认为问题更深入。这是因为我有另一个名为address.rb的模型。它是多态的。
协会是:
address.rb
belongs_to :addressable, :polymorphic => true
profile.rb
has_many :addresses, as: :addressable
在我的个人资料中,我有:
<%= render 'profiles/geography' %>
在我的地理部分,我有:
<% if @profile.addresses.any? %>
<%= @profile.addresses.first.country_name.titlecase %>
<% else %>
<span class="profileeditlink">
<%= link_to "Add your location", new_address_path %>
</span>
<% end %>
控制台显示我有4个已保存的地址。我只有一个用户。
配置文件显示页面显示其他条件(即添加地址),即使保存了地址也是如此。
在我的个人资料显示页面上成功显示的唯一属性是配置文件表中的属性。所有关联的属性都显示为空白。那些有资格/愿景的人,不能存入数据库。
我无法弄清楚为什么这一切都搞砸了。
这个问题的另一个角度是我的资格表现在已经保存了一个条目。它显示在rails控制台中。但是,我的资格部分应该显示该条目,只显示标题。
<div class="profilequalificationstitle">
Qualifications
</div>
</div>
</div>
<% Qualification.all.sort_by(&:year_earned).each do |qual| %>
<div class="row">
<div class="col-md-12">
<div class="profilequalifications">
<%= @profile.try(:qualification).try(:title) %>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="intpolmin">
<%= @profile.try(:qualification).try(:year_earned) %>:
</div>
</div>
<div class="col-md-8">
<div class="intpolmin">
<%= @profile.try(:qualification).try(:institution) %>
</div>
</div>
</div>
<% end %>
</div>
</div>
采取以下建议:
我在配置文件控制器中更改了我的强params定义的格式,以便它不使用rails scaffolding提供的格式,而是显示为:
def profile_params
params.require(:profile).permit(:user_id, :title, :hero, :overview, :research_interest, :occupation, :external_profile,
:working_languages, :tag_list,
user_attributes: [:avatar],
personality_attributes: [:average_day, :fantasy_project, :preferred_style],
vision_attributes: [:long_term, :immediate_challenge],
qualifications_attributes: [:id, :level, :title, :year_earned, :institution, :_destroy] )
end
所有相关型号仍然使用导轨脚手架格式 - 即:
def vision_params
params[:vision].permit(:profile_id, :long_term, :immediate_challenge)
end
配置文件控制器中的新方法有:
def new
@profile = Profile.new
@profile.qualifications.build
@profile.vision.build
@profile.personality.build
authorize @profile
end
至于表达关联的方式,其个人偏好是保持嵌套属性与关联。我可以看到这个建议使用较少的行来实现相同的东西,但我的首选是与嵌套属性声明的关联。
我的个人资料模型关联是:
belongs_to :user
has_many :addresses, as: :addressable
has_one :personality
accepts_nested_attributes_for :personality
has_many :qualifications
accepts_nested_attributes_for :qualifications, reject_if: :all_blank, allow_destroy: true
has_one :vision
accepts_nested_attributes_for :vision
我的个人资料显示页面然后尝试以多种方式使用其他模型中的属性。当我尝试使用用户模型中的属性(配置文件属于用户)时,它可以成功运行。
当我尝试使用属于个人资料的模型中的属性时,它不起作用。
我有以下使用这些属性的方法 - 没有一个工作:
Qualifications
<div class="row">
<div class="col-md-12">
<div class="profilequalifications">
<!-- @qualification.award.profile -->
</div>
</div>
</div>
然后 - 我的视觉和个性的嵌套形式采用以下格式:
<%= f.simple_fields_for :profile do |f| %>
<%= f.simple_fields_for :vision do |ff| %>
<div class="form-inputs">
<%= ff.input :long_term, as: :text, :label => "What is your long term research vision?", :input_html => {:rows => 10} %>
<%= ff.input :immediate_challenge, as: :text, :label => "What do you see as the immediate challenge to be addressed in pursuit of your long-term vision?", :input_html => {:rows => 10} %>
</div>
<% end %>
<% end %>
我的资格表格略有不同,因为它使用cocoon gem添加功能以重复该表格以获得多种资格。
进一步调查
我找到了线索。
在我的终端中,我可以看到在表单中创建属性的补丁之后,出现了一个错误:
Unpermitted parameter: profile
考虑到这一点,我发现了这些帖子中的每一个,提出了以下解决方案:
解决方案1:更改配置文件控制器中的强参数以包含父级的ID(在我的情况下:profile_id):
Unpermitted Parameters: profile (NestedAttributes) - RAILS 4
我尝试改变:
vision_attributes: [:id, :long_term, :immediate_challenge],
到
vision_attributes: [:id, :profile_id, :long_term, :immediate_challenge],
结果:无差异 - 产生相同的错误。
解决方案2:更改表格
Nested attributes - Unpermitted parameters Rails 4
考虑到这个建议,我尝试将愿景形式改为:
<%= f.simple_fields_for :profile_attributes do |f| %>
<%= f.simple_fields_for :vision, @profile.vision do |ff| %>
<div class="form-inputs">
<%= ff.input :long_term, as: :text, :label => "What is your long term research vision?", :input_html => {:rows => 10} %>
<%= ff.input :immediate_challenge, as: :text, :label => "What do you see as the immediate challenge to be addressed in pursuit of your long-term vision?", :input_html => {:rows => 10} %>
</div>
<% end %>
<% end %>
结果:没有区别 - 同样的错误结果。
解决方案3:在配置文件控制器中表达强参数的方式的进一步变化:
Rails 4 Nested Attributes Unpermitted Parameters
更改嵌套强params在配置文件控制器中表示的方式:
vision_attributes: [:id, :profile_id, :long_term, :immediate_challenge],
到
:vision_attributes[:id, :profile_id, :long_term, :immediate_challenge],
结果:
新错误:
语法错误,意外&#39;,&#39;,expecting =&gt; ... ng_term,:immediate_challenge],... ^ /Users/mem/cl/cf3/app/controllers/profiles_controller.rb:95:语法错误,意外&#39;,&#39;,期待keyword_end / Users /mem/cl/cf3/app/controllers/profiles_controller.rb:96:语法错误,意外&#39;,&#39;,期待keyword_end /Users/mem/cl/cf3/app/controllers/profiles_controller.rb: 97:语法错误,意外&#39;)&#39;,期待keyword_end
另一种解决方案
我发现了这篇文章:http://www.sitepoint.com/complex-rails-forms-with-nested-attributes/#adding-an-address
采用该教程中显示的方法,我尝试创建一个表单助手,其中包含:
module FormHelper
def setup_profile(profile)
profile.vision ||= Vision.new
profile
end
end
(我不知道定义主体第二行的单词配置文件意味着什么),但它与教程中用户/地址的方法一致。
然后我将个人资料表单更改为:
<%= f.simple_fields_for (setup_profile(profile)) do |f| %>
<%= render 'visions/form', f: f %>
<% end %>
将我的愿景改为:
<div class="form-inputs">
<%= ff.input :long_term, as: :text, :label => "What is your long term research vision?", :input_html => {:rows => 10} %>
<%= ff.input :immediate_challenge, as: :text, :label => "What do you see as the immediate challenge to be addressed in pursuit of your long-term vision?", :input_html => {:rows => 10} %>
</div>
当我保存这些更改并再试一次时,我收到此错误:
undefined local variable or method `profile' for #<#<Class:0x007fe113fcd680>:0x007fe11f2769d0>
错误消息指向配置文件表格的这一行:
<%= f.simple_fields_for (setup_profile(profile)) do |f| %>
我不知道此错误消息的含义,但我认为这是因为个人资料应该是&#39; @ profile&#39;或者&#39;:个人资料&#39; - 我不知道为什么,它经常出现这种情况。
如果我将此行更改为:
<%= f.simple_fields_for (setup_profile(@profile)) do |f| %>
我收到此错误:
undefined method `long_term' for #<Profile:0x007fe11c241c38>
我认为这个错误意味着表单正在寻找一个名为&#34; long_term&#34;的属性。在配置文件表中,而不是愿景表。
如果我将此行更改为:
<%= f.simple_fields_for (setup_profile(@profile.vision)) do |f| %>
我在表单助手中遇到此错误:
undefined method `vision' for #<Vision:0x007fe117e95278>
在我继续随机尝试之前,任何人都可以看到我尝试实施网站点文章中显示的解决方案是否存在问题?
答案 0 :(得分:1)
首先,你的params方法需要修复:
std
为了澄清,您应该阅读strong params on github。
你写得太多了;这是它应该看起来的样子:
def profile_params
params.require(:profile).permit(...
创建#app/models/profile.rb
class Profile < ActiveRecord::Base
has_many :qualifications
has_one :vision
accepts_nested_attributes_for :qualifications, :vision #-> has to match association name
end
时,您需要构建关联对象(除非它们已经存在):
profile
这将允许您使用以下表格:
#app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
def new
@profile = Profile.new
@profile.qualifications.build
@profile.build_vision
end
end
这应创建一个新的#app/views/profiles/new.html.erb
<%= form_for @profile do |f| %>
<%= f.fields_for :qualifications do |q| %>
<%= q.text_field :title %>
... etc ...
<% end %>
<%= f.fields_for :vision do |v| %>
<%= v.text_field :long_term %>
... etc ...
<% end %>
<%= f.submit %>
<% end %>
&amp;根据需要关联profile
/ qualification
个对象。
您的vision
多态关联不应与上述有任何关系。
虽然最初会引起混淆,但多态关联基本上使您能够引用可在许多不同情况下使用的关联。它的多态性这一事实并不重要。
IE Rails只会使用addressable
是否has_many :addresses
。