Как автоматически обновить модель с помощью has_many через ассоциацию?

#ruby-on-rails #ruby

Вопрос:

У меня есть 3 модели: Поставщик (который унаследован от Пользователя STI), Автомобиль и Реклама. И имеют следующие ассоциации:

 class Provider < User
  has_many :advertisements, foreign_key: :user_id, dependent: :destroy
  has_many :cars, through: :advertisements, foreign_key: :user_id, dependent: :destroy
end

class Car < ApplicationRecord
  belongs_to :user
  has_one :advertisement
end

class Advertisement < ApplicationRecord
  belongs_to :user, foreign_key: :user_id
  belongs_to :car, foreign_key: :car_id
end
 

Моя схема выглядит так:

   create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.string "type"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

  create_table "providers", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "cars", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
    t.string "user_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.string "body_type"
    t.string "brand"
    t.string "fuel_type"
    t.float "engine_capacity"
    t.string "color"
  end

  create_table "advertisements", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
    t.string "ad_type"
    t.integer "user_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "car_id"
    t.text "description"
    t.string "title"
  end
 

Все работает хорошо, но когда я создаю экземпляр автомобиля, я хочу видеть автоматическое заполнение в отношении, например: поставщик = current_user.cars, и я вижу пустое отношение #<ActiveRecord::Associations::CollectionProxy []>

Чтобы исправить это, мне нужно добавить в контроллер моих автомобилей следующее:

     def create
        @car = Car.new(car_params)
        current_user.cars << @car

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

def car_params
    params.require(:car).permit(:body_type, :model, :brand, :fuel_type, :engine_capacity, :condition, :color, :price, :year, :user_id)
end
 

Но я думаю, что это не прямой путь, и он должен быть автоматически заполнен магией некоторых ассоциаций. Пожалуйста, помогите решить эту проблему.

Ответ №1:

Вы должны сделать что-то вроде:

 def create
    @car = current_user.cars.build(car_params)
  ....
end
 

Затем ActiveRecord позаботится о том, чтобы установить правильные ассоциации между объектами.

Комментарии:

1. Добавил эту строку в контроллер, но в консоли по-прежнему получаю пустой массив: p = Поставщик. последний (идентификатор совпадает с current_user), затем p.cars = #<ActiveRecord::Ассоциации::CollectionProxy []>

2. Я предполагаю, что вам нужно использовать accepts_nested_attributes_for модель поставщика для cars

3. @NaveenHonestRaj такое же поведение

4. @arieljuod на самом деле это работает, но мне нужно добавить еще одну строку кода, например: current_user.save

5. @JessieScinor, вместо этого ты должен сделать что-то подобное @car.save . Я предполагал, что у вас это уже было, так как ваш текущий код делает .new это, а не .create