简体   繁体   English

Rails – 保存现有记录 ID 而不是复制记录

[英]Rails – saving existing record id instead of duplicating record

I am learning Rails at the moment, I'm a total novice.我现在正在学习 Rails,我完全是个新手。 I'm hoping to be able to get help from the Rails experts here.我希望能够在这里得到 Rails 专家的帮助。 I've tried to search through StackOverflow but haven't been able to find a solution.我试图通过 StackOverflow 进行搜索,但未能找到解决方案。

So there are a Pet model that has Breed model for its references which references to Category model, So the 3 models:所以有一个Pet model 其参考Category model 有Breed model,所以 3 个模型:

class Pet < ApplicationRecord
  belongs_to :breed
  accepts_nested_attributes_for :breed
  has_one :category, through: :breed

class Breed < ApplicationRecord
  belongs_to :category
  has_many :pets, dependent: :destroy
  accepts_nested_attributes_for :category

class Category < ApplicationRecord
  has_many :breeds, dependent: :destroy
  has_many :pets, through: :breed

I have already set up the form using simple_form .我已经使用simple_form设置了表单。 When a new Pet is created, the user is able to select the existing Category options that is associated with Breed .创建新宠物时,用户可以selectBreed关联的现有Category选项。 Then in the form, a breed.name attribute is set as a text_field that user can input their own.然后在表单中,将breed.name属性设置为用户可以输入自己的text_field字段。 Please below the nested attribute part:请在嵌套属性部分下方:

...
<!-- Nested Breed & Category Attributes -->
<%= f.simple_fields_for :breed, Breed.new do |breed| %>
  <%= breed.error_notification %>
  <%= breed.error_notification message: breed.object.errors[:base].to_sentence if breed.object.errors[:base].present? %>
  <div class="form-row">

    <div class="form-group col-md-4">
      <%= breed.association :category, collection: Category.order(:id),
                                       label: "Animal Category", required: true %>
    </div>

    <div class="form-group col-md-8">
      <%= breed.input :name, required: true,
                             label: "Breed", placeholder: "Domestic short hair",
                             hint: "Type 'unknown', if unsure", class: "form-control" %>
    </div>
  </div>
<% end %>

So my question is, how can I save the new pet with an existing breed_id record without duplicating it with a different breed_id ?所以我的问题是,如何使用现有的breed_id记录保存新宠物而不用不同的breed_id复制它?

So at the moment, I already have an existing record of breed_id: 1 , that consists of category_id: 1 (for Cat), and name: 'domestic short hair' – if I create a new pet with these same values in the form, it will duplicate the record, it's supposed to save breed_id: 1 , but instead, the new pet is saved under breed_id: 15 ...所以目前,我已经有一个breed_id: 1的现有记录,它由category_id: 1 (for Cat), and name: 'domestic short hair'组成——如果我在表格中创建一个具有这些相同值的新宠物,它会复制记录,它应该保存breed_id: 1 ,但是新宠物保存在breed_id: 15 ...

When I check on the console :当我检查console时:

irb(main):001:0> Breed.find_by_name("domestic short hair")
  Breed Load (6.8ms)  SELECT "breeds".* FROM "breeds" WHERE "breeds"."name" = $1 LIMIT $2  [["name", "domestic short hair"], ["LIMIT", 1]]
=> #<Breed id: 1, name: "domestic short hair", category_id: 1, created_at: "2021-08-14 13:12:41.266154000 +0000", updated_at: "2021-08-14 13:12:41.266154000 +0000">
irb(main):002:0> Breed.last
  Breed Load (8.2ms)  SELECT "breeds".* FROM "breeds" ORDER BY "breeds"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Breed id: 15, name: "domestic short hair", category_id: 1, created_at: "2021-08-16 04:08:31.602249000 +0000", updated_at: "2021-08-16 04:08:31.602249000 +0000">

What's the best way to update my controller / model / form helper (I'm not sure which one), so it prevents the duplicating?更新我的controller / model / form helper的最佳方法是什么(我不确定是哪一个),这样可以防止重复? I currently don't have a breeds_controller , and only using the pets_controller , which is a basic one from Scaffolding:我目前没有breeds_controller ,只使用pets_controller ,这是 Scaffolding 中的基本控制器:

pets_controller.rb

  def show
  end

  # GET /pets/new
  def new
    @pet = Pet.new
    @pet.build_breed
  end
  
  # GET /pets/1/edit
  def edit
  end
  
  # POST /pets or /pets.json
  def create
    @pet = current_user.pets.new(pet_params)

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

...

  private

  def pet_params
   params.require(:pet).permit(:owner_id, :name, :dob, :gender, :bio, :instagram,
                                breed_attributes: [:name, :category_id])
  end

I've tried to write a before_save:existing_breed_record in the model breed.db , which I think is wrong...我试图在 model breed.db中写一个before_save:existing_breed_record ,我认为这是错误的......

class Breed < ApplicationRecord
  belongs_to :category
  has_many :pets, dependent: :destroy 
  accepts_nested_attributes_for :category
  before_save :existing_breed_record

  private

    def existing_breed_record
     if self.find_by(category_id, name).exists?
      return self.id
    end
end

Here is my schema.db这是我的schema.db

  create_table "breeds", force: :cascade do |t|
    t.string "name"
    t.bigint "category_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["category_id"], name: "index_breeds_on_category_id"
  end

  create_table "categories", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "pets", force: :cascade do |t|
    t.bigint "owner_id", null: false
    t.bigint "breed_id", null: false
    t.string "name"
    t.date "dob"
    t.integer "gender"
    t.string "bio"
    t.string "instagram"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["breed_id"], name: "index_pets_on_breed_id"
    t.index ["owner_id"], name: "index_pets_on_owner_id"
  end

I read from the guides that there is find_or_create_by method that I think is what I need, but I'm not sure where and how to implement it...我从指南中读到我认为我需要的是find_or_create_by方法,但我不确定在哪里以及如何实现它......

For database and Rails experts, for the sake of learning, how would you suggest I do this better next time?对于数据库和 Rails 专家,为了学习,您建议我下次如何做得更好? Should I have the breed as a string attribute/column to the Pet model and directly associate the Category model to Pet instead?我是否应该将breed作为宠物 model 的字符串属性/列,并将Category model 直接关联到宠物?

if you wanted to use the nested form, you could add the before_save method to Pet如果你想使用嵌套形式,你可以将before_save方法添加到Pet

\\pet.rb

before_save :check_existing_breed


def check_existing_breed
  if self.breed&.name and breed = Breed.find_by(name: self.breed&.name)
    self.breed = breed
  end
end

With the help of my teacher, we finally found a solution.在老师的帮助下,我们终于找到了解决办法。 It's a bit messy, but it no longer duplicates any existing record!它有点乱,但它不再重复任何现有记录!

First of, thanks to @Yunwei.W, as suggested, I added @pet.breed in my nested form (was previously :breed, Pet.new do... :首先,感谢@Yunwei.W,按照建议,我在我的嵌套形式中添加了@pet.breed (以前是:breed, Pet.new do...

...
<!-- Nested Breed & Category Attributes -->
<%= f.simple_fields_for :breed, @pet.breed do |breed| %>
...

Then in the pets_controller.rb :然后在pets_controller.rb中:

def create
 # Preventing duplicates when breed name mathes exsiting record
 breed = Breed.find_by_name(params[:pet][:breed_attributes][:name]) || Breed.create(name: params[:pet][:breed_attributes][:name], category_id: params[:pet][:breed_attributes][:category_id])

 @pet = current_user.pets.new(pet_params.except(params[:pet][:breed_attributes][:name]))

 @pet.breed = breed

...

end

There is definitely a better solution than this, but I'm so glad it finally works after having this blocker for 3 days.肯定有比这更好的解决方案,但我很高兴在使用此拦截器 3 天后它终于起作用了。 Thank you everyone who has contributed to help!感谢所有为帮助做出贡献的人! Really appreciate it!真的很感激!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM