sn0wtroopeer
sn0wtroopeer

Reputation: 102

Saving an array of params in Rails

I have in my Rails 5 api project two models: Places and Beacons (Place has_many Beacons, foreign key: place_id). This API accepts JSON, such as this one:

{
  "place":{
    "name": "bedroom"
  },
  "beacon":{
    "SSID": "My Wi-Fi",
    "BSSID": "00:11:22:33:44:55",
    "RSSI": "-55"
  }
}

This JSON works just fine, with these classes:

def create
    @place = Place.new(place_params)
    @beacon = Beacon.new(beacon_params)


    if @place.save
      @[email protected]
      if @beacon.save
        render :json => {:place => @place, :beacon => @beacon}, status: :created, location: @places
      else
        render json: @beacon.errors, status: :unprocessable_entity
      end
    else
      render json: @place.errors, status: :unprocessable_entity
    end
end

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

    # Only allow a trusted parameter "white list" through.
    def place_params
      params.require(:place).permit(:name)
    end

  def beacon_params
    params.require(:beacon).permit(:SSID, :BSSID, :RSSI)
  end

However, I want that to pass multiple Beacons objects in the same JSON in an array (even no beacons at all). How can I save then all beacons in the parameter array and generate a response containing all of them?

Upvotes: 1

Views: 1359

Answers (1)

James Bowden
James Bowden

Reputation: 191

I'm assuming Place has_many :beacons. If so, you can use nested attributes. This lets you assign and update a nested resource, in this case Beacons. First, in your Place model:

accepts_nested_attributes_for :beacons

Then, change your place_params method in your controller to permit the beacon's nested attributes:

def place_params
  params.require(:place).permit(:name, beacons_attributes: [:id, :SSID, :BSSID, :RSSI])
end

And your json:

{
  "place":{
    "name": "bedroom",
    "beacons_attributes": [
      {
        "SSID": "My Wi-Fi",
        "BSSID": "00:11:22:33:44:55",
        "RSSI": "-55"
      }, { 
        //more beacons here 
      }
    ]
  },

}

You can have zero, one, or more beacons, and can do the same when updating as well if you include the beacons' id's.

You also won't have to create the @beacon manually, and can just do this: @place = Place.new(place_params), and it'll automatically create the beacons and associate them to the Place.

You can read more here, if you'd like more information or clarification: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Edit: I missed where you asked how to include the beacons in the response. The quickest way is to just include it in the json rendering:

render :json => @place.to_json(:include => :beacons)

You can use Active model serializers (https://github.com/rails-api/active_model_serializers), jbuilder (https://github.com/rails/jbuilder), or more simply just override the to_json method on your model.

Upvotes: 1

Related Questions