Search code examples
ruby-on-railsangularjsrestful-architecture

How i can create Guests in another controller (for me it is Events)


I am stuck on creating Guests in my Events controller.

An error from rails:

undefined method `permit' for [{"name"=>"John"}, {"name"=>"Mike"}]:Array

How can I save Guests from Events controller, please help.

This is my EventsController:

class EventsController < ApplicationController

 def create
    @event = Event.create(event_params)
    @guest = Guest.create(guest_params)

    respond_with [@event, @guest]

  end

private
  def event_params
    params.require(:event).permit(:name, :description, :date)
  end

  def guest_params
    params.require(:guests).permit(:name)
  end
end

So, this is JSON from the view:

date:"25.07.2016"
description:"Biggest Show"
guests:[{name: "John"}, {name: "Mike"}]
name:"Night Show"

My class Event.rb:

class Event < ActiveRecord::Base
  has_many :guests
  def as_json(options = {})
    super(options.merge(include: :guests))
  end
end

My class Guest.rb:

class Guest < ActiveRecord::Base
  belongs_to :event
  def as_json(options = {})
    super
  end
end

And Guest controller (if it more helpful):

class GuestsController < ApplicationController
  respond_to :json
  def index
    respond_with Guest.all
  end

  def show
    respond_with Guest.find(params[:id])
  end

  def create
    respond_with Guest.create(guest_params)
  end


  private
  def guest_params
    params.require(:guest).permit(:name)
  end
end

Solution

  • Since guests in your view is an array of hashes [{name: "John"}, {name: "Mike"}], you should do something like this in your controller:

    # app/controllers/events_controller.rb
    class EventsController < ApplicationController
      def create
        @event = Event.create(event_params)
        @guests = guests_params[:guests].map { |guest|
          Guest.create(name: guest[:name], event: @event)
        }
    
        respond_with @event
      end
    
      private
        def event_params
          params.require(:event).permit(:name, :description, :date)
        end
    
        def guests_params
          params.require(:event).permit(:guests)
        end
    end
    

    Alternatively you could change your view to return guests: { name_1: "John", name_2: "Mike", name_3: ... ] and then use a permit method, that expects the index of the guest:

    # app/controllers/events_controller.rb
    class EventsController < ApplicationController
      def create
        ...
        @guests = (1..max_index).map { |index|
          Guest.create(guest_params(index).merge({ event: @event }))
        }
        ...
      end
    
      private
        ...
        def guest_params index
          params.require(:guests).permit("name_#{index}")
        end
    end
    

    I have not checked the code against the interpreter, but I think you get the idea :)

    EDIT: changed event_params.guests to params[:event][:guests], since guests is not a method or field of the event_params hash. Also removed guests from the permit method, because it could give an error when creating the event. But I am not sure if this is a good practice solution or if it even works exactly that way. It's still just to give the idea :)