在Rails 4控制器中获取关联对象的正确方法

时间:2014-01-09 18:57:02

标签: ruby-on-rails ruby-on-rails-4

这可能是一个重复的问题,因为它似乎非常基本,但我不能以正确的方式搜索。正如你所看到的,我是Rails的新手。

在Rails 4中,我有两个对象:Text和Project。文字belongs_to :project和项目has_many :texts

创建新文本时,用户必须从现有项目的下拉列表中选择项目 - 他们永远不会通过文本控制器创建新项目。

所以,我已将:project' in texts_controller.rb`列入白名单:

def text_params

  params.require(:text).permit(:type, :sort_title, :date_created, :project,
  ...

但现在create方法必须这样做:

def create
  @text = Text.new(text_params.except('project'))
  @text.project = Project.find(text_params['project'])
...

为了避免Project(...) expected, got String(...)。显然我可以重命名param,但我的表单代码如下:

<p>Select Project</p>
<%= f.collection_select :project, Project.all, :pid, :display_label  %> 

我无法弄清楚如何在那里更改参数名称。

我可能完全错了,实际上是做对了,但我真的很怀疑; Rails对我来说感觉不太习惯,即我实际上并没有传递一个项目,只是它的id,而且,尽管我只是一个小小的方式,我觉得我打破了“瘦控制器,胖模型“口头禅。可能还有其他问题。这样做的“Rails方式”是什么? TIA!

修改 也许这是我的考验,这很糟糕。这是我用来测试这个的工厂:

require 'faker'

FactoryGirl.define do

  factory :text do |t| 
    t.project { FactoryGirl.create(:project) } # not sure if this is right...

    # TODO: creator and contributor, and then catch validation errors in tests
    t.abstract { Array.new(rand(0..2)) { Faker::Lorem.paragraph(rand(1..7)) } }
    t.alternative_title { Array.new(rand(0..5)) { Faker::Lorem.sentence(5,true,3) } }
    t.audience { Array.new(rand(0..2)) { Faker::Lorem.sentence(5,true,3) } }
    t.citation { Array.new(rand(0..2)) { Faker::Lorem.sentence(5,true,3) } }
    t.date_created { rand(900..2000) }
    t.description { Array.new(rand(0..10)) { Faker::Lorem.paragraph(1,true,3) } }
    t.extent { Array.new(rand(0..2)) { Faker::Lorem.sentence(5,true,3) } }
    t.has_part { Array.new(rand(0..20)) { Faker::Lorem.sentence(3,true,5) } }
    t.language { Array.new(rand(0..5)) { Faker::Lorem.sentence(1,false,3) } }
    t.provenance { Array.new(rand(0..2)) { Faker::Lorem.paragraph(rand(1..7)) } }
    t.publisher { Array.new(rand(0..2)) { Faker::Lorem.sentence(3,true,3) } }
    t.rights { Array.new(rand(0..4)) { Faker::Lorem.sentence(5,true,3) } }
    t.series { Array.new(rand(0..2)) { Faker::Lorem.sentence(3,true,5) } }
    t.sort_title { Faker::Lorem.sentence(2,true,5) }
    t.subject { Array.new(rand(0..7)) { Faker::Lorem.sentence(1,true,3) } }
    t.title { Array.new(rand(1..2)) { Faker::Lorem.sentence(3,true,5) } }
    t.toc { Array.new(rand(0..2)) { Faker::Lorem.sentence(5,true,3) } }
    t.type "Text"
  end

end

所有POST测试都失败了:https://github.com/pulibrary/pul-store/blob/development/spec/controllers/texts_controller_spec.rb#L46-L82

1 个答案:

答案 0 :(得分:1)

我假设项目已经存在且用户只是从集合下拉列表中选择它们。

将您的强参数方法更改为:

def text_params
  params.require(:text).permit(:type, :sort_title, :date_created, :project_id,
  ...

然后你的收藏品选择字段名称:

<p>Select Project</p>
<%= f.collection_select :project_id, Project.all, :pid, :display_label  %> 

最后,将控制器操作更改为:

def create
  @text = Text.new(text_params)
  ...

由于Text belongs_to项目,它将具有project_id属性,您可以直接从params分配,并且一旦分配它就能够获取关联:

@text = Text.new project_id: 1
@text.project # => #<Project id: 1>

希望有所帮助。