Home > Software design >  Rails API Controller Update Action -- How to add many-to-many
Rails API Controller Update Action -- How to add many-to-many

Time:03-11

I have a Rails Api that feeds a Vue front end. I have two main models, Contacts and Outlets, with a many to many relationship via a join table ContactOutlets. I am trying to figure out how in the Contacts controller to add an association to an outlet.

I recognize, I could call the ContactOutlet create action separately, but it seems wasteful if Rails can handle this on the back end. I want vue to call contact#update once.

Contact Model:

class Contact < ApplicationRecord
  has_many :contact_outlets
  has_many :outlets, through: :contact_outlets
  has_many :calls

  validates_uniqueness_of :email
  validates_uniqueness_of :name

end

Outlet Model:

class Outlet < ApplicationRecord
  has_many :contact_outlets
  has_many :contacts, through: :contact_outlets
  has_many :calls

  validates_uniqueness_of :website
end

ContactOutlet:

class ContactOutlet < ApplicationRecord
  belongs_to :contact
  belongs_to :outlet

  validates_uniqueness_of :contact_id, :scope => :outlet_id
end

Contacts Controller:

class ContactsController < ApplicationController
  before_action :set_contact, only: %i[ show update destroy ]

  # GET /contacts
  def index
    @contacts = Contact.all

    render json: @contacts, include: :outlets
  end

  # GET /contacts/1
  def show
    render json: @contact, include: :outlets
  end

  # POST /contacts
  def create
    @contact = Contact.new(contact_params)

    if @contact.save
      render json: @contact, status: :created, location: @contact
    else
      render json: @contact.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /contacts/1
  def update
    if @contact.update(contact_params)
      render json: @contact, include: :outlets
    else
      render json: @contact.errors, status: :unprocessable_entity
    end
  end

  # DELETE /contacts/1
  def destroy
    @contact.destroy
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_contact
      @contact = Contact.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def contact_params
      params.require(:contact).permit(:name, :email, :bio, :image_url)
    end
end

CodePudding user response:

Solved this. In case anyone else is looking the models above are fine. made some adjustments to the contact_params to allow access to the outlets array. Then fixed the update action. Full controller code below:

class ContactsController < ApplicationController
  before_action :set_contact, only: %i[ show update destroy ]

  # GET /contacts
  def index
    @contacts = Contact.all

    render json: @contacts, include: :outlets
  end

  # GET /contacts/1
  def show
    render json: @contact, include: :outlets
  end

  # POST /contacts
  def create
    @contact = Contact.new(contact_params)

    if @contact.save
      render json: @contact, status: :created, location: @contact
    else
      render json: @contact.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /contacts/1
  def update
    if @contact.outlets
      @contact.outlets.delete_all
    end
    if params[:outlets]
      contactOutlets = params[:outlets]
      contactOutlets.each do |outlet|
        @contact.outlets << Outlet.find(outlet[:key])
      end
    end
    if @contact.update(contact_params)
      render json: @contact, include: :outlets
    else
      render json: @contact.errors, status: :unprocessable_entity
    end
  end

  # DELETE /contacts/1
  def destroy
    @contact.destroy
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_contact
      @contact = Contact.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def contact_params
      params.require(:contact).permit(:name, :email, :bio, :image_url, outlet_ids:[])
    end
end
  • Related