[英]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
.创建新宠物时,用户可以select
与Breed
关联的现有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.