2017-08-12 76 views
0

我与导轨5.1.2和Ruby 2.2.6工作Ruby on Rails的:在数组初始化

我有以下类别:

class Idea < ApplicationRecord 
    validates :title, presence: true 
    validates :description, presence: false 
    has_many :discussions 
end 

class Discussion < ApplicationRecord 
    validates :title, presence: true 
    belongs_to :idea 

    def initialize(title) 
    @title = title 
    end 
end 

idea创作,我想在属性discussions中添加默认discussion。由于我是红宝石和Rails的新手,我不知道哪种方法可以做到这一点。这是我尝试失败的原因。

在思想控制,我试过在idea创建,以创建默认discussion,如下所示:

class IdeasController < ApplicationController 

    def create 
    discussion = Discussion.new "Main thread" 
    @idea = Idea.new(idea_params) 
    @idea.discussions << discussion 
    @idea.save 
    redirect_to ideas_path 
    end 

    private 
    def idea_params 
     params.require(:idea).permit(:title) 
    end 
end 

这驱使我在控制器中的错误:

undefined method `<<' for nil:NilClass 

上line

@idea.discussions << discussion 

我认为这是由于uninit在我的idea中ialized discussions阵列。但是,指南指出,具有声明has_many的任何类将继承方法<<,如this guide中所述。但是,也许这是唯一的想法被保存至少一次后?

我尝试手动初始化我的控制器中的数组。

@idea.discussions = [] 

这有助于消除错误,但我很惊讶这不会自动完成。此外,discussion未保存在数据库中。我尝试添加的声明autosave的理念类,有没有效果:

has_many :discussions, autosave: true 

我一点点丢失。最后,我只想在其创建和保存之间添加一个discussion,并将其保存在idea之间。什么是最好的方法?

感谢您的任何帮助。

回答

3

Discussion已经是ActiveRecord对象,所以你不需要initialize方法。只需拨打Discussion.new即可开箱即用。

要创建默认Discussion创建Idea时只需执行以下操作: @idea.build_discussion。这将在您的Idea模型上实例化新的Discussion关联。当您保存Idea时,它将自动保存Discussion对象,并自动将其与Idea关联。

编辑:为了简化答案,这里是代码:

def create 
    @idea = Idea.new 
    @idea.build_discussion(title: 'Main Thread') 

    if @idea.save 
    redirect_to ideas_path 
    else 
    redirect_to :new 
    end 
end 

编辑2:因为你通过Idea建立Discussion,你需要把它添加到您的IdeaControllerstrong_params

def idea_params 
    params.require(:idea).permit(
    ... 
    discussion_attributes: [ 
     :id, 
     :title, 
     .. 
    ] 
) 
end 

编辑3:对不起,我没注意你的关联类型。更新到这一点:

def create 
    @idea = Idea.new 
    @idea.discussions.new(title: 'Main Thread') 

    if @idea.save 
    redirect_to ideas_path 
    else 
    redirect_to :new 
    end 
end 
+0

听起来很不错。现在,我面临另一个问题:**未定义的方法'build_discussion'为# **。 –

+2

'build_xxx'用于'has_one'关系,而不是'has_many'。 –

+1

您可能还需要在Discussion模型中添加'accept_nested_attributes_for:idea'。有关更多详细信息,请参见https://www.pluralsight.com/guides/ruby-ruby-on-rails/ruby-on-rails-nested-attributes。 –

2

首先,不会覆盖initialize在ActiveRecord模型,除非你知道自己在做什么。你的对象已经定义了一个initialize方法,你不能看到它,因为它是继承的。如果在不接受正确的参数集的情况下重写并调用super,则会引入错误。

ActiveRecord为您提供了一个简单的哈希语法,用于在初始化时设置属性。您可以立即使用Discussion.new(title: 'Title')

如果您始终想要使用默认值discussion创建您的ideas,则可以将其移至before_createcallback的模型中。

class Idea < ApplicationRecord 
    validates :title, presence: true 
    validates :description, presence: false 
    has_many :discussions 
    before_create :build_default_discussion 

    private 

    def build_default_discussion 
    discussions.build(title: 'Main Thread') 
    end 
end 

在这里,您之前的每个新idea正在调用私有方法build_default_discussion被持久化。当您在Idea.new.saveIdea.create或任何其他代理方法创建新的Idea时,会自动发生这种情况,该方法会在应用程序的任何位置创建新的Idea

+2

非常好的方法,如果你想要一个新的创意与每个想法。这种方式对于使用控制台或任务创建新想法也非常有用。 – Vlad

+0

我想避免在控制器中做这件事,而你的主张更符合我的希望。感谢您的建议,我会应用它。我只有一个问题:为什么'build_default_discussion'是变量'discuss'没有'@'? –

+0

对于任何对'before_create'等活动记录回调感兴趣的人,让我们来看看[本指南](http://guides.rubyonrails.org/active_record_callbacks。html) –

相关问题