Rails - 添加不在模型中的属性并更新模型属性

发布于 2025-01-07 14:34:15 字数 1406 浏览 1 评论 0原文

我的表单中有 3 个字段不在我的数据库中:opening_type、opening_hours、opening_minutes。我想用这 3 个字段更新主要属性“opening”(在数据库中)。

我尝试了很多不起作用的事情。

实际上我有:

  attr_accessor :opening_type, :opening_hours, :opening_minutes

  def opening_type=(opening_type)
  end
  def opening_type
    opening_type = opening.split("-")[0] if !opening.blank?
  end

  def opening_hours=(opening_hours)
  end
  def opening_hours
    opening_hours = opening.split("-")[1] if !opening.blank?
  end  

  def opening_minutes=(opening_minutes)
  end
  def opening_minutes
    opening_minutes = opening.split("-")[2] if !opening.blank?    
  end

我尝试添加类似的内容:

  def opening=(opening)
    logger.info "WRITE"

    if !opening_type.blank? and !opening_hours.blank? and opening_minutes.blank?
      opening = ""
      opening << opening_type if !opening_type.blank?
      opening << "-" 
      opening << opening_hours if !opening_hours.blank?
      opening << "-" 
      opening << opening_minutes if !opening_minutes.blank?
    end
    write_attribute(:opening, opening)
  end

  def opening
    read_attribute(:opening)
  end

但是,不会调用访问器方法,并且我认为如果调用了访问器,那么 opening_type、opening_hours、opening_minutes 也是空的...

我认为我不需要 before_save 回调,应该这样做这重写了访问器。

笔记: - 轨道 3.0.5, - opening_type,:opening_hours,:opening_minutes 可能为空

编辑:我更新了我的代码

I have 3 fields in my form witch are not in my database: opening_type, opening_hours, opening_minutes. I want to update the main attribute "opening" (in database) with these 3 fields.

I tried lot of things that doesn't work.

Actually I have:

  attr_accessor :opening_type, :opening_hours, :opening_minutes

  def opening_type=(opening_type)
  end
  def opening_type
    opening_type = opening.split("-")[0] if !opening.blank?
  end

  def opening_hours=(opening_hours)
  end
  def opening_hours
    opening_hours = opening.split("-")[1] if !opening.blank?
  end  

  def opening_minutes=(opening_minutes)
  end
  def opening_minutes
    opening_minutes = opening.split("-")[2] if !opening.blank?    
  end

I tried adding something like:

  def opening=(opening)
    logger.info "WRITE"

    if !opening_type.blank? and !opening_hours.blank? and opening_minutes.blank?
      opening = ""
      opening << opening_type if !opening_type.blank?
      opening << "-" 
      opening << opening_hours if !opening_hours.blank?
      opening << "-" 
      opening << opening_minutes if !opening_minutes.blank?
    end
    write_attribute(:opening, opening)
  end

  def opening
    read_attribute(:opening)
  end

But, the accessors methods are not called and I think opening_type, opening_hours, opening_minutes were empty too if the accessors were called...

I think I don't need a before_save callback and should do this rewriting the accessors.

Notes:
- Rails 3.0.5,
- opening_type, :opening_hours, :opening_minutes could be empty

EDIT: I updated my code

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

裸钻 2025-01-14 14:34:15

请注意,attr_readerattr_writerattr_accessor 只是用于定义您自己的方法的宏。

# attr_reader(:foo) is the same as:
def foo
  @foo
end

# attr_writer(:foo) is the same as:
def foo=(new_value)
  @foo = new_value
end

# attr_accessor(:foo) is the same as:
attr_reader(:foo)
attr_writer(:foo)

目前,您的 setter 方法没有做任何特殊的事情,因此如果您只是切换到 attr_accessor ,您的代码将变得更干净。

您的另一个问题是您的 opening= 方法永远不会被调用,这是有道理的,因为您的代码中没有任何地方调用它。你真正想要的是在所有单独的部分都设置好之后设置你的开口。现在没有简单的方法可以做到这一点,但 Rails 确实有一个 before_validation 回调,您可以在其中放置在设置值之后但在验证运行之前运行的代码:

class Shop < ActiveRecord::Base

  attr_accessor :opening_type, :opening_hours, :opening_minutes

  before_validation :set_opening

  private
  def set_opening
    return unless opening_type && opening_hours && opening_minutes
    self.opening = opening_type + "-" + opening_hours + "-" + opening_minutes
  end
end

Note that attr_reader, attr_writer and attr_accessor are just macros for defining your own methods.

# attr_reader(:foo) is the same as:
def foo
  @foo
end

# attr_writer(:foo) is the same as:
def foo=(new_value)
  @foo = new_value
end

# attr_accessor(:foo) is the same as:
attr_reader(:foo)
attr_writer(:foo)

At the moment, your setter methods aren't doing anything special, so if you just switch to attr_accessor your code will become cleaner.

Your other issue is that your opening= method is never being called, and this makes sense because there's nowhere in your code calling it. What you really want is for your opening to be set after all of the individual parts have been set. Now there's no trivial way to do this, but Rails does have a before_validation callback where you can put code that runs after values have been set but before the validation runs:

class Shop < ActiveRecord::Base

  attr_accessor :opening_type, :opening_hours, :opening_minutes

  before_validation :set_opening

  private
  def set_opening
    return unless opening_type && opening_hours && opening_minutes
    self.opening = opening_type + "-" + opening_hours + "-" + opening_minutes
  end
end
小帐篷 2025-01-14 14:34:15

而不是

attr_reader :opening_type, :opening_hours, :opening_minutes

你需要

attr_accessor :opening_type, :opening_hours, :opening_minutes
attr_reader :opening_type, :opening_hours, :opening_minutes

hf...

// :opening_type, :opening_hours, :opening_minutes 是真实字段吗?如果是,那么您只需要这个?

attr_accessor:打开
attr_reader :打开

instead of

attr_reader :opening_type, :opening_hours, :opening_minutes

you need

attr_accessor :opening_type, :opening_hours, :opening_minutes
attr_reader :opening_type, :opening_hours, :opening_minutes

hf...

// Are :opening_type, :opening_hours, :opening_minutes real fields? If yes then you just need this?

attr_accessor :opening
attr_reader :opening

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文