【问题标题】:can't create a record in a database无法在数据库中创建记录
【发布时间】:2015-05-01 09:36:56
【问题描述】:

我使用的是 rails 4.2 版和 ruby​​ 2.2.0 版。我正在尝试将记录保存到 lollypops 表。没有例外说明原因。

任务:创建并保存member 后,我想通过在成员控制器的create 方法中调用create_lollypop(@member.id) 来填充lollypops 表,如下所示:

 #   POST /members
 #   POST /members.json
  def create

 @member = Member.create(members_params)                               
   return unless request.post?

   @member.save!
   self.current_user = @member
   c = Country.find(@member.country_id)
   @member.update_attributes(
   :country_code=>c.code)
   create_lollypop(@member.id) #From here I want to create lollypop
   MemberMailer.signup_notification(@member).deliver_now

   redirect_to(:controller => '/admin/members', :action => 'show',
   :id=> @member.id)
   flash[:notice] = "Thanks for signing up! Check your email now to 
   confirm that    your email is correct!"

   rescue ActiveRecord::RecordInvalid
   load_data
   render :action => 'new'

  end

def create_lollypop(member_id)
 @member = Member.find(member_id)      
    Lollypop.create(
    :member_id=>@member.id,
    :product_name=>'lollypop',
    :product_price=>100,
    :email=>@member.email,
    :house_flat => @member.house_flat,    
    :street=>@member.street,
    :city_town=>@member.city_town,
    :country =>@member.country,   
    :postcode_index=>@member.postcode_index,
    :name=>@member.name)
end 

“成员”已创建,但“棒棒糖”表未填充。这些关联是:

会员模型:

 has_one :lollypop, :dependent=>:destroy

LOLLYPOP 模型

  belongs_to :member

如果我使用通用 SQL 命令,则会填充 lollypops 表,但我不想这样做:

def self.create_lollypop(member_id)
   member = Member.find(member_id) 
ActiveRecord::Base.connection.execute("insert into lollypops (member_id,product_name,product_price,email,house_flat,street,city_town,country,postcode_index,name)
   values(#{member.id},'lollypop',#{100},'#{member.email}','#{member.house_flat}','#{member.street}','#{member.city_town}','#{member.country_code}','#{member.postcode_index}','#{member.name}')")  

end 

欢迎任何建议。谢谢。

【问题讨论】:

  • 棒棒糖模型中是否有一些验证?
  • 将Lollypop.create 更改为Lollypop.create!,你没有处理失败,所以这会引发错误,这是找出问题的最简单方法。
  • 你能检查一下你的“create_lollypop()”吗,你正在使用“@member”。

标签: mysql ruby-on-rails ruby database controller


【解决方案1】:

在你的 create_lollypop() 中,你没有定义@member。

def create_lollypop(member_id)
  @member = Member.find member_id
  Lollypop.create!(
    :member_id=>@member.id,
    :product_name=>'lollypop',
    :product_price=>100,
    :email=>@member.email,
    :house_flat => @member.house_flat,    
    :street=>@member.street,
    :city_town=>@member.city_town,
    :country =>@member.country,   
    :postcode_index=>@member.postcode_index,
    :name=>@member.name
  )
end 

也使用创建!因此,如果任何验证失败,则会引发异常。所以它会帮助你解决问题。

【讨论】:

  • 看,她在创建成员的同一个请求中调用了create_lollypop,所以@member 在相同的范围内仍然可用,它有点不同,但它应该可以工作,访问@ 987654324@ 至少部分
【解决方案2】:

目前尝试直接在控制器中使用关联方法 create_lollypop 创建棒棒糖。在创建控制器方法中使用此代码,请注意 create_lollypop 方法将填充(member_id 字段自动):

@member = Member.create(members_params)                               
   return unless request.post?

   @member.save!
   self.current_user = @member
   c = Country.find(@member.country_id)
   @member.update_attributes(
   :country_code=>c.code)
   #From here I want to create lollypop
   @member.create_lollypop(
     :product_name=>'lollypop',
    :product_price=>100,
    :email=>@member.email,
    :house_flat => @member.house_flat,    
    :street=>@member.street,
    :city_town=>@member.city_town,
    :country =>@member.country,   
    :postcode_index=>@member.postcode_index,
    :name=>@member.name
    )
   MemberMailer.signup_notification(@member).deliver_now

   redirect_to(:controller => '/admin/members', :action => 'show',
   :id=> @member.id)
   flash[:notice] = "Thanks for signing up! Check your email now to 
   confirm that    your email is correct!"

   rescue ActiveRecord::RecordInvalid
   load_data
   render :action => 'new'

【讨论】:

    【解决方案3】:

    这并不完全是一个答案,更像是提示和注释,它有点长,希望你不要介意。

    • return unless request.post?
      

      这更像是一个 php 的东西而不是一个 rails 的东西,在 rails 中路由已经在检查这个,所以你不需要在控制器内部做这个检查,如果它不是 post 它将是路由到别处。

    • @member = Member.create(members_params)
      return unless request.post?
      @member.save!
      

      创建后保存是没有意义的,因为create已经保存了数据,如果你是为了bangsave!做的,那么你可以使用create with bangcreate!,更不用说你做了在成员创建后进行重定向检查,所以如果这确实有效,它会给你留下流浪成员。

    • c = Country.find(@member.country_id)
      @member.update_attributes(:country_code=>c.code)
      

      如果你的关联正确,你不需要像这样保存代码,因为会员知道这个country_id属于一个国家。

      所以将这个添加到成员模型中

      class Member < ActiveRecord::Base
        has_one :lollypop, dependent: :destroy
        belongs_to :country
      end
      

      这样你总是可以调用@member.country来返回国家对象,然后代码可以来自那里,比如@member.country.code,或者你可以写一个方法来缩短它

      def country_code
        country.code
      end
      

      这种方式将通过额外的查询获得代码,但它有一个优势,如果您出于任何原因更改一个国家/地区的代码,您不需要循环访问拥有该国家/地区的所有成员并更新他们的代码,您还可以使用#delegate

      进一步缩短此时间
    •  @member.save!
       @member.update_attributes(:country_code=>c.code)
      

      在这里,您在保存成员后更新成员的属性,这有点浪费,因为您正在执行 2 次查询以获取 1 次查询可以完成的操作,以编程方式它是正确的并且可以工作,但这对扩展,当更多用户开始使用您的应用时,数据库会更忙,响应会更慢。

      相反,我建议推迟创建成员,直到您拥有所需的所有数据

      @member = Member.new(members_params) # this won't save to the database yet
      @memeber.code = Country.find(@member.country_id).code
      @member.save
      

      当所有数据都准备好保存时,这只会在最后执行 1 次查询。

    • redirect_to(:controller => '/admin/members', :action => 'show', :id=> @member.id)
      

      这没问题,但您的路线中可能有一个更好的较短路径名,例如 members_admin_path,通过在终端中执行 bin/rake routes 来检查您的路线名称。

      redirect_to members_admin_path(id: @member)
      
    • redirect_to ...
      flash[:notice] = "message"
      

      我不确定这是否可行,因为需要返回重定向,但是当您在其后添加 flash 时,重定向将在没有 flash 的情况下发生,或者 flash 将被设置并返回,因为它是最后一个语句,但是重定向不会发生,不确定会发生哪个,要修复它,您可以简单地交换两个语句,先创建闪存然后重定向,或者使用更方便的方式在重定向时设置闪存,因为那是支持

      redirect_to ....., notice: 'my message'
      
    • rescue ActiveRecord::RecordInvalid
      load_data
      render :action => 'new'
      

      这将完成这项工作,但它不是传统的,人们倾向于使用软save,然后对返回值做一个 if 条件,无论是真还是假,这是一个简短的布局

      # prepare @member's data
      if @member.save
        # set flash and redirect
      else
        load_data
        render :new
      end
      
    • 棒棒糖创作
      现在有一些关于这个的事情,首先你有控制器中的方法,这很糟糕,因为它不应该是控制器的关注点,第二种方法 self.create_lollypop 更好,因为它是在模型级别创建的,但它是类方法,那么更好的方法是将其创建为成员方法,这样创建lollypop 的成员已经知道数据,因为它是他自己的,注意我不需要调用@member 因为我已经内部成员,像id、email 这样简单的调用将返回成员的数据

      # inside member.rb
      def create_lollypop
        Lollypop.create!(
          member_id: id,
          product_name: 'lollypop',
          product_price: 100,
          email: email,
          house_flat: house_flat,
          street: street,
          city_town: city_town,
          country: country,   
          postcode_index: postcode_index,
          name: name
        )
      end
      

      如果您愿意,也可以将其添加为创建后回调

      after_create :create_lollypop
      

      ps:此方法名称可能会与 ActiveRecords create_lollypop 方法冲突,因此您应该为该方法选择一个不同的名称。

    【讨论】:

    • 感谢 Mohammad 评论我的编码。我是一个业余程序员,所以你的分析对我很有价值。
    【解决方案4】:

    按照 Mohammad 对我的建议,我将 Lollypop.create 更改为 Lollypop.create!和 运行我的代码时,弹出一个验证错误。改正后和 将我的代码更改为:

     Lollypop.create!( 
     :member_id=> @member.id,  
     :product_name=>'lollypop',
     :product_price=>100,
     :email=>@member.email,
     :house_flat => @member.house_flat,    
     :street=>@member.street,
     :city_town=>@member.city_town,
     :country =>@member.country_code,   
     :postcode_index=>@member.postcode_index,
     :name=>@member.name
    )
    

    “棒棒糖”表已填充。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多