表单中的Rails虚拟属性不是从表单或控制台更新db

时间:2018-03-06 22:33:08

标签: ruby-on-rails ruby database forms virtual-attribute

因此,在我的Rails Web应用程序中,我有一段代码,提示未成年用户在创建帐户时输入父/监护人电子邮件。在我的数据库中,我想将其存储为相应的ID,但用户自然会想要输入电子邮件。

我表单的这一部分看起来像这样:

<%= f.label :guardian_email, "Guardian Email" %>
<%= f.text_field :guardian_email, class: 'form-control' %>

我模型中的相应代码如下所示:

def guardian_email
    User.find_by_id(guardian_id).email if guardian_id
end

def guardian_email=(g_email)
    guardian = User.find_by_email(g_email)
    print guardian.id
    self.guardian_id = guardian.id
    print self.guardian_id
end

(我在调试时添加的打印行)但是,提交表单不会更新所需的属性。然后我尝试从控制台输入:

User.find_by_email("example-5@site.org").guardian_email=("example-7@site.org")

我得到了输出:

User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "example-5@site.org"], ["LIMIT", 1]]
User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "example-7@site.org"], ["LIMIT", 1]]
88 => "example-7@mtb.org" 

但是当我之后加载用户时,属性guardian_id仍为零。奇怪的是两个打印语句都返回了正确的值(在这种情况下为8)但是从未发生过赋值,尽管打印出的第二个8是值“self.guardian_id”。

我已经按照railscast#16 - 虚拟属性来获取我现在拥有的代码,谢谢。

编辑:

上述代码无法运行的原因是因为我允许控制器中的实际属性而不是虚拟属性。虽然最大指出了这个代码中也存在其他一些不良做法。

我仍然不明白的是,在控制台中调用guardian_email =()方法仍然不会更新属性,但它在网站上运行正常。

2 个答案:

答案 0 :(得分:0)

对于一项简单的任务来说,这是一种非常复杂的方法。

class User  < ApplicationRecord
  belongs_to :guardian,
    class_name: 'User',
    optional: true

  def guardian_email=(email)
    self.guardian ||= User.find_by_email(email)
    @guardian_email = email
  end

  def guardian_email
    @guardian_email || guardian.try(:email)
  end
end

class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :email
      # ...
      t.belongs_to :guardian, foreign_key: { to_table: :users }
      t.timestamps
    end
    add_index :users, :email, unique: true
  end
end

您还需要一个自定义验证,如果guardian_email不为空,则会检查该电子邮件是否确实属于用户。

class User  < ApplicationRecord
  # ...
  validate :guardian_exists, unless: ->{ self.guardian_email.blank? }

  # ...

  private

  def guardian_exists
    errors.add(:guardian_email) unless guardian || User.find_by_email(guardian_email)
  end
end

答案 1 :(得分:0)

没有进行任何更改的原因是因为在用户控制器中我包含guardian_id而不是guardian_email作为允许的参数。尝试使用虚拟属性更新模型时,在控制器中应该允许表单中包含的虚拟属性。