Rails - 如何更新记录,然后根据要修改的记录的值动态更新另一个模型的值?

时间:2015-06-24 02:16:44

标签: ruby-on-rails ruby

问题

假设我有一个名为ServiceMenu的脚手架,它只包含一个下拉菜单,其中包含 Brakes Pads 消声器的3个值。 我有Service模型,它在名为Tech的模型上存储属于用户的所有服务。每个tech都可以添加service_menu制动 Pads Muffler )中的任何一个到他们的db配置文件,名为services

我想到的问题是,如果我更新任何一个ServiceMenu名称从 Brakse Brakes techs仍将在个人资料中使用旧的service_menu名称。由于错误或者只是想更新ServiceMenu名称,我发现自己会做很多内务处理,更新超过1000条记录。

文件

service_menu.rb

class ServiceMenu < ActiveRecord::Base
  has_many :services
end

service.rb

class Service < ActiveRecord::Base
  belongs_to :tech
  belongs_to :service_menu
end

service_menus_controller.rb

def update
    respond_to do |format|
  if @service_menu.update(service_menu_params)
    format.html { redirect_to @service_menu, notice: 'Service menu was successfully updated.' }
  else
    @position_count = ServiceMenu.count
    format.html { render :edit }
    end
end

service_controller

def new
  @service = current_tech.services.build
end



def create
  @service = current_tech.services.build(service_params)

  respond_to do |format|
    if @service.save
      format.html { redirect_to @service, notice: 'Service was successfully created.' }
      format.json { render :show, status: :created, location: @service }
    else
      format.html { render :new }
      format.json { render json: @service.errors, status: :unprocessable_entity }
    end
  end
end 

模式

create_table "service_menus", force: :cascade do |t|
    t.string   "name",                      limit: 255
    t.datetime "service_icon_updated_at"
    t.integer  "service_icon_file_size",    limit: 4
    t.string   "service_icon_content_type", limit: 255
    t.string   "service_icon_file_name",    limit: 255
    t.integer  "position",                  limit: 4
    t.datetime "created_at",                            null: false
    t.datetime "updated_at",                            null: false
  end


  create_table "services", force: :cascade do |t|
    t.string   "name",       limit: 255
    t.integer  "tech_id", limit: 4
    t.datetime "created_at",             null: false
    t.datetime "updated_at",             null: false
  end


  create_table "techs", force: :cascade do |t|
    t.string   "email",                  limit: 255, default: "", null: false
    t.string   "username",               limit: 255
    t.datetime "avatar_updated_at"
    t.integer  "avatar_file_size",       limit: 4
    t.string   "avatar_content_type",    limit: 255
    t.string   "avatar_file_name",       limit: 255
    t.string   "encrypted_password",     limit: 255, default: "", null: false
    t.string   "reset_password_token",   limit: 255
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          limit: 4,   default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip",     limit: 255
    t.string   "last_sign_in_ip",        limit: 255
    t.datetime "created_at",                                      null: false
    t.datetime "updated_at",                                      null: false
    t.string   "first_name",             limit: 255
    t.string   "last_name",              limit: 255
 end

问题

我可以随时执行将services数据库中的多个记录动态更新为ServiceMenu中更新名称的任务吗? 用词来说:

  • ServiceMenu上的记录从错误 Brakse 更新为 Brakes
  • 更新ServiceMenu上的记录后,Rails会在services db中找到name列中= Brakse
  • 的所有值
  • name列中的所有 Brakse 值更新为制动
  

修改

每当我在ServiceMenu下拉菜单上更新任何内容时,请执行此类操作。

if @service_menu.update(service_menu_params)
@service.update.where(name: "Old `ServiceMenu` value which , ie.**Brakse**", "The new `ServiceMenu` value which is now **Brakes**")

请帮忙说明如何做到这一点。 非常感谢任何帮助。

3 个答案:

答案 0 :(得分:0)

除非我错过了一些问题的细微差别,否则您需要将服务项目从Brakse重命名为Brake - 关联将保持有效。

当然,这假定services表有一个name字段,但如果没有看到你的架构,很难知道。

如果这不是正确答案,请显示整个架构,而不仅仅是关联。

答案 1 :(得分:0)

在Rails中,您可以通过在实体之间创建模型关系来实现这一点。在您的情况下,具体来说,看起来像这样:

class Tech < ActiveRecord::Base
  has_many :services, inverse_of: :tech
end

class Service < ActiveRecord::Base
  belongs_to :tech, inverse_of: :services
  belongs_to :service_menu, inverse_of :services
end

class ServiceMenu < ActiveRecord::Base
  has_many :services, inverse_of: :service_menu
end

现在,如果Service模型在数据库中有一个名称列(在这种情况下应该是这样),那么只要在数据库中更新该属性,它也将为每个用户更新,因为它们所有都与同一个数据库表有关系。

简而言之,如果您为模型添加适当的关系(如上所列),您将不必担心任何类型的问题。这就是面向对象编程的美妙。

请注意:您当前的模型结构的设置方式,Service类,Tech类以及{{{} ServiceMenu类需要外键引用1}}类。迁移看起来像这样:

rails generate migration AddTechAndServiceMenuRefToServices tech:references service_menu:references

该迁移会将tech_idservice_menu_id列添加到您的Service类,从而在您的不同模型之间创建正确的关系。

答案 2 :(得分:0)

这些模型名称ServiceMenu和Service在此上下文中确实令人困惑,应该分别是Service和RenderedService。话虽如此,让我们看看你需要什么才能让它工作,而根本不需要更新声明。

将以下关系添加到组合中:

class ServiceMenu < ActiveRecord::Base
  has_many :services
end

class Service < ActiveRecord::Base
  belongs_to :service_menu
  belongs_to :tech
end

class Tech < ActiveRecord::Base
  has_many :services
end

服务模型现在使用其名称来引用ServiceMenu,这是您的混淆所在。而不是名称,让服务模型通过创建类似的迁移使用service_menu_id引用ServiceMenu:

rails generate migration AddServiceMenuIdToServices service_menu_id:references

完成这些更改后,您需要调整代码以使用服务模型中的新service_menu_id列。

如果以前你做过类似的事情:

s = Service.new(name: 'Brakes', tech: Tech.find_by(name: 'Bob'))

你现在应该这样做:

s = Service.new(service_menu: ServiceMenu.find_by(name: 'Brakes'), tech: Tech.find_by(name: 'Bob'))

现在,Saving s将保存对当前名为&#39; Brakes&#39;的特定ServiceMenu项目的引用。如果您将来将此特定ServiceMenu项目的名称更改为&#34; Barkes&#34;该更改将自动反映在服务模型中,因为它不再在服务记录中存储服务菜单项的名称。

如果您之前使用的是:

s = Service.find(100)
puts s.name

要检索服务所指的服务菜单项的名称,现在您可以使用以下内容:

s = Service.find(100)
puts s.service_menu.name

您在服务模型中仍然有一个名称字段需要使用迁移删除。如果您在此系统中有现有数据,则需要使用名称字段中的数据填充所有服务模型的service_menu_id字段。