How to parse nested JSON object in Rails? - ruby-on-rails

I'm sending the following JSON to Rails 4.1.0
Started POST "/orders.json" for 127.0.0.1 at 2015-08-11 15:19:34 +0200
Processing by OrdersController#create as JSON
Parameters: {"order"=>{"name"=>"Jon", "surname"=>"Do", "line_items_attributes"=>[{"work_id"=>16, "quantity"=>1, "total_price"=>34.5}, {"work_id"=>12, "quantity"=>2, "total_price"=>40}]}}
Unpermitted parameters: line_items_attributes
but I'm getting Unpermitted parameters error. My Order model:
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :dispatch_method
belongs_to :payment_method
has_many :line_items, :dependent => :destroy
accepts_nested_attributes_for :line_items
end
My orders_controller.rb
class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
def index
#orders = Order.all
end
def show
end
def new
#order = Order.new
end
def edit
end
def create
#order = Order.create(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render action: 'show', status: :created, location: #order }
else
format.html { render action: 'new' }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #order.update(order_params)
format.html { redirect_to #order, notice: 'Order was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
def destroy
#order.destroy
respond_to do |format|
format.html { redirect_to orders_url }
format.json { head :no_content }
end
end
private
def set_order
#order = Order.find(params[:id])
end
def order_params
params.require(:order).permit(:name, :surname, line_items_attributes: [:id, :work_id, :quantity, :total_price])
end
end
I'm able to create and save a new instance of order, but not of a line_item.

You can try to redefine your order_params like this:
def order_params
json_params = ActionController::Parameters.new(JSON.parse(params[:order]))
return json_params.require(:name, :surname).permit(line_items_attributes: [:id, :work_id, :quantity, :total_price])
end
As you see, I am parsing params[:order] to avoid parsing the full params var. You might need to add another json level here but I hope you get the idea.

something like this
render :json => #booking, :include => [:paypal,
:boat_people,
:boat => {:only => :name, :include => {:port => {:only => :name, :include => {:city => {:only => :name, :include => {:country => {:only => :name}}}}},
:boat_model => {:only => :name, :include => {:boat_type => {:only => :name}}}}}]

Related

Rails: Post JSON to API Using Rails and HTTParty

I'm fairly new to API in Rails, and so I will need some assistance for the issue that I am facing.
All I want is to create a record on the database of the API through a POST request from my application.
That is to create a record on both databases (my database and the on the database of the API through a POST request from my application) whenever I create a book.
So this is what I've done so far:
For the app that will consume the API I am using the HTTParty gem.
I have tried to implement in my create action of the Books Controller using the code below:
#result = HTTParty.post(' https://www.pingme.com/wp-json/wplms/v1/user/register',
:body => { :name => '#{name}',
:author => '#{author}',
:description => '#{description}',
:category_id => '#{category_id}',
:sub_category_id => '#{sub_category_id}'}.to_json,
:headers => { 'Content-Type' => 'application/json', 'Authorization' => '77d22458349303990334xxxxxxxxxx' })
Here is my Books Controller for creating books
require 'httparty'
class BooksController < ApplicationController
include HTTParty
before_action :set_book, only: [:show, :edit, :update, :destroy]
before_action :authenticate_admin!, except: %i[show index]
skip_before_action :verify_authenticity_token
# GET /books
# GET /books.json
def index
#books = Book.search(params[:keywords]).paginate(:page => params[:page], :per_page => 9).order('created_at DESC')
end
# GET /books/1
# GET /books/1.json
def show
end
# GET /books/new
def new
#book = Book.new
end
# GET /books/1/edit
def edit
end
# POST /books
# POST /books.json
def create
#book = Book.new(book_params)
respond_to do |format|
if #book.save
format.html { redirect_to #book, notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: #book }
else
format.html { render :new }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
#result = HTTParty.post(' https://www.pingme.com/wp-json/wplms/v1/user/register',
:body => { :name => '#{name}',
:author => '#{author}',
:description => '#{description}',
:category_id => '#{category_id}',
:sub_category_id => '#{sub_category_id}'}.to_json,
:headers => { 'Content-Type' => 'application/json', 'Authorization' => '77d22458349303990334xxxxxxxxxx' })
end
# PATCH/PUT /books/1
# PATCH/PUT /books/1.json
def update
respond_to do |format|
if #book.update(book_params)
format.html { redirect_to #book, notice: 'Book was successfully updated.' }
format.json { render :show, status: :ok, location: #book }
else
format.html { render :edit }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.json
def destroy
#book.destroy
respond_to do |format|
format.html { redirect_to books_url, notice: 'Book was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
#book = Book.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:name, :author, :description, :category_id, :sub_category_id)
end
end
But it still doesn't create these books on the database of the API through the post request when I create books.
Please any form of assistance will be highly appreciated.
Thank you.
Check you logs when you do the request, but I suspect you need to change your body to:
{
:book => {
:name => '#{name}',
:author => '#{author}',
:description => '#{description}',
:category_id => '#{category_id}',
:sub_category_id => '#{sub_category_id}'
}
}.to_json
Note that book key at the top is the difference.
Following contributions from #paulo-fidalgo and #tejasbubane, I found a working solution to the issue.
Here is the corrected HTTParty Post Request
#results = HTTParty.post(' https://www.pingme.com/wp-json/wplms/v1/user/register',
:body => {
:name => "#{#book.name}",
:author => "#{#book.author}",
:description => "#{#book.description}",
:category_id => "#{#book.category_id}",
:sub_category_id => "#{#book.sub_category_id}"}.to_json,
:headers => {
'Content-Type' => 'application/json',
'Authorization' => '77d22458349303990334xxxxxxxxxx'
}
)

Rails 5 - Strong Parameters for Nested Attributes

I am having trouble structuring my nested attributes for my model Request.
The data is being passed in the correct way from my POST action.
What am I missing to whitelist these parameters?
Appreciate any help.
Console Output
Started POST "/requests" for 127.0.0.1 at 2017-06-08 10:57:15 -0400
Processing by RequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"fmvhoPxVpcHoqOd32mO/HJMrfaPUd+KbNqDJiSRs78U44Y0uL3prpTfU6wmw7PAwv0b+mRHXOGMLvD9bsZpxnw==", "request"=>{"concierge_name"=>"Alex", "concierge_number"=>"954-123-4567", "concierge_email"=>"alex#email.com", "client_name"=>"Adam", "client_number"=>"954-765-4321", "client_email"=>"adam#email.com", "hotel_employee"=>"0", "concierge_service"=>"0", "vip_promoter"=>"0", "arriving_with_client"=>"1", "client_alone"=>"0", "males"=>"", "females"=>"1", "table_minimum"=>"1000", "arrival_time(1i)"=>"2017", "arrival_time(2i)"=>"6", "arrival_time(3i)"=>"8", "arrival_time(4i)"=>"14", "arrival_time(5i)"=>"56", "table_location_ids"=>["1"], "drink_attributes"=>[{"id"=>"1", "quantity"=>"1"}, {"id"=>"2", "quantity"=>""}, {"id"=>"3", "quantity"=>""}, {"id"=>"4", "quantity"=>""}], "chaser_ids"=>["1"], "comments"=>""}, "commit"=>"Submit"}
Completed 500 Internal Server Error in 8ms (ActiveRecord: 0.0ms)
ActiveModel::UnknownAttributeError (unknown attribute 'drink_attributes' for Request.):
app/models/request.rb
class Request < ApplicationRecord
has_many :request_drinks
has_many :drinks, through: :request_drinks
accepts_nested_attributes_for :drinks
end
app/model/drink.rb
class Drink < ApplicationRecord
has_many :request_drinks
has_many :requests, through: :request_drinks
end
app/model/request_drink.rb
class RequestDrink < ApplicationRecord
belongs_to :request
belongs_to :drink
end
app/controllers/request_controller.rb
class RequestsController < ApplicationController
before_action :set_request, only: [:show,
:edit,
:update,
:destroy]
def index
#requests = Request.search(params[:term], params[:filter], params[:page])
end
def show
end
def new
#request = Request.new
#drinks = Drink.active
end
def edit
end
def create
#request = Request.new(request_params)
respond_to do |format|
if #request.save
format.html { redirect_to thanks_path, notice: 'Request was successfully created.' }
format.json { render :show, status: :created, location: #request }
else
format.html { render :new }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #request.update(request_params)
format.html { redirect_to #request, notice: 'Request was successfully updated.' }
format.json { render :show, status: :ok, location: #request }
else
format.html { render :edit }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
def destroy
#request.destroy
respond_to do |format|
format.html { redirect_to requests_url, notice: 'Request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_request
#request = Request.find(params[:id])
end
def request_params
params.require(:request).permit(:concierge_name,
:concierge_number,
:concierge_email,
:client_name,
:client_number,
:client_email,
:hotel_employee,
:concierge_service,
:vip_promoter,
:arriving_with_client,
:client_alone,
:people,
:males,
:females,
:table_minimum,
:arrival_time,
:comments,
:drink_attributes => [:id, :quantity]
)
end
end
app/views/requests/_form.html.erb
...
<div class="field-3">
<h4>Drinks</h4>
<% #drinks.all.each do |d| %>
<%= hidden_field_tag "request[drink_attributes][][id]", d.id %>
<%= number_field_tag "request[drink_attributes][][quantity]" %>
<%= d.name %>
<br />
<% end %>
</div>
...
You need to use the plural form of the object (i.e. drinks) when using nested attributes.
So, in your request_params change:
:drink_attributes => [:id, :quantity]
to:
:drinks_attributes => [:id, :quantity]
An you need to update your form too:
...
<%= hidden_field_tag "request[drinks_attributes][][id]", d.id %>
<%= number_field_tag "request[drinks_attributes][][quantity]" %>
...

Rails, How i can create grouped_select?

I'm new in rails and i need a help.
I wanna to do a grouped selection on rails but i dont know how i can do it.
i have 3 db tables cars, car_brands and car_models. When i add new car i need to select car model, how i can do it with gtouped selection.
models/car_brand.rb
class CarBrand < ActiveRecord::Base
has_many :cars
has_many :car_models
mount_uploader :logo, CarBrandImgUploader
end
models/car_model.rb
class CarModel < ActiveRecord::Base
has_many :cars
belongs_to :car_brand
end
cars_controller.rb
class CarsController < ApplicationController
before_action :set_car, only: [:show, :edit, :update, :destroy]
before_action :set_model, only: [:index, :new, :edit]
# GET /cars
# GET /cars.json
def index
#cars = Car.all
end
# GET /cars/1
# GET /cars/1.json
def show
end
# GET /cars/new
def new
#car = Car.new
end
# GET /cars/1/edit
def edit
end
# POST /cars
# POST /cars.json
def create
#car = Car.new(car_params)
respond_to do |format|
if #car.save
if params[:ImagesCars]
params[:ImagesCars]['image'].each do |a|
#ImagesCar = #car.ImagesCars.create!(:image => a, :car_id => #car.id)
end
end
format.html { redirect_to #car, notice: 'Car was successfully created.' }
format.json { render :show, status: :created, location: #car }
else
format.html { render :new }
format.json { render json: #car.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /cars/1
# PATCH/PUT /cars/1.json
def update
respond_to do |format|
if #car.update(car_params)
if params[:ImagesCars]
params[:ImagesCars]['image'].each do |a|
#ImagesCar = #car.ImagesCars.create!(:image => a, :car_id => #car.id)
end
end
format.html { redirect_to #car, notice: 'Car was successfully updated.' }
format.json { render :show, status: :ok, location: #car }
else
format.html { render :edit }
format.json { render json: #car.errors, status: :unprocessable_entity }
end
end
end
# DELETE /cars/1
# DELETE /cars/1.json
def destroy
#car.destroy
respond_to do |format|
format.html { redirect_to cars_url, notice: 'Car was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_car
#car = Car.find(params[:id])
end
def set_model
#models = CarModel.all
#brands = CarBrand.all
end
# Never trust parameters from the scary internet, only allow the white list through.
def car_params
params.require(:car).permit(:title_en, :keys_en, :description_en, :text_en, :title_fr, :keys_fr, :description_fr, :text_fr, :title_ru, :keys_ru, :description_ru, :text_ru, :title_es, :keys_es, :description_es, :text_es, :model_id, :brand_id, :price_day, :price_week, :p_info, :images_cars => [:id, :car_id, :image])
end
end
cars/new.html.haml
= simple_form_for(#car, html: { role: 'form', multipart: true }) do |f|
= f.input :price_day, as: :integer, input_html: {class: 'form-control', placeholder: 'Price Day ej: 150'}
= f.cktext_area :text_en, as: :text, input_html: { class: 'form-control' }, :label => 'EN Website Content Text EN'
=f.input :model_id, collection: #models, as: :grouped_select, group_method: :brand_id
= f.submit 'Save'
i get this error:
undefined method `map' for nil:NilClass
Please help or explain how i can do the grouped selection.
Thx

uninitialized constant ProductsController::Offer error?

I have an issue, I cant figure out what the problem is with the product controller error,
I will not render the product index view page which is what i want to work.
my code is here as follows :
offers controller
class OffersController < ApplicationController
attr_accessible :product , :reserve_price
def your_offer
#your_offer = Offer.new
end
def new
#offer = Offer.new = :your_offer
end
end
and Products Controller
class ProductsController < ApplicationController
before_filter :authenticate, :except => [:index, :show]
# GET /products
# GET /products.xml
def index
#offer = Offer.new
#products = Product.search(params[:search_query])
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #products }
end
end
# GET /products/1
# GET /products/1.xml
def show
#product = Product.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #product }
end
end
# GET /products/new
# GET /products/new.xml
def new
#product = Product.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #product }
end
end
# GET /products/1/edit
def edit
#product = Product.find(params[:id])
end
# POST /products
# POST /products.xml
def create
#product = current_user.products.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to(#product, :notice => 'Product was successfully created.') }
format.xml { render :xml => #product, :status => :created, :location => #product }
else
format.html { render :action => "new" }
format.xml { render :xml => #product.errors, :status => :unprocessable_entity }
end
end
end
# PUT /products/1
# PUT /products/1.xml
def update
#product = Product.find(params[:id])
respond_to do |format|
if #product.update_attributes(params[:product])
format.html { redirect_to(#product, :notice => 'Product was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #product.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.xml
def destroy
#product = Product.find(params[:id])
#product.destroy
respond_to do |format|
format.html { redirect_to(products_url) }
format.xml { head :ok }
end
end
end
Offer Model
class Offer < ActiveRecord::Base
belongs_to :product
has_many :reserve_prices
attr_accessible :product, :offer , :reserve_price
validates_presence_of :offer
validate :ensure_meets_reserve_price
private
def ensure_meets_reserve_price
if amount < self.product.reserve_price
errors.add(:amount, "does not meet reserve price")
end
end
private
def reserve_price
product.reserve_price
end
def your_offer
#your_offer = Offer.new
end
def new
#offer = Offer.new = :your_offer
end
end
product index viex snippet
<%= form_for #offer do |f| %>
<%= f.text_field :your_offer %>
<%= f.submit "Make Offer" %>
<% end %>
Could any one see where my eror is ?
Its complaining about #offer = Offer.new
Did you run the migration and restarted the server after creating offers?
Did you declare it as a resource in config/routes.rb as
resources :products, :shallow => true do
resources :offers # or at least just this line
end
Edit:
Get rid of this line and try again
attr_accessible :product, :offer , :reserve_price
is :offer a column in the offers table?
You cannot have columns from another model in attr_accessible.

Ruby on Rails: many-to-many association undefined methode on creation

I have set up members and teams models using has_many through association.
member.rb
has_many :teams, :through => :team_members
has_many :team_members
team.rb
has_many :members, :through => :team_members
has_many :team_members
team_member.rb
belongs_to :member
belongs_to :team
When I try to create a new team, I get this error:
undefined method `name' for nil:NilClass
params are:
{"utf8"=>"✓",
"authenticity_token"=>"aXpMxWxGlhogfn9EbBWciSjoMrYXbPxG8Kzha14na58=",
"team"=>{"name"=>"Ruby",
"email"=>"email#email.com",
"language"=>"En",
"link"=>"",
"logo"=>#<ActionDispatch::Http::UploadedFile:0xb3907f0 #original_filename="You-Are-Great-.gif",
#content_type="image/gif",
#headers="Content-Disposition: form-data; name=\"team[logo]\"; filename=\"You-Are-Great-.gif\"\r\nContent-Type: image/gif\r\n",
#tempfile=#<File:/tmp/RackMultipart20120723-1907-m3bi79>>},
"commit"=>"Create Team"}
The create method in teams_controller.rb is:
#team = Team.new(params[:team])
The team doesn't get created unless I assign the attributes manually one by one like
#team = Team.new(:name => params[:team][:name], :email => params[:team][:email]...)
and so! any ideas why?
EDIT:
teams_controller.rb:
class TeamsController < ApplicationController
# GET /teams
# GET /teams.json
def index
#teams = Team.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #teams }
end
end
# GET /teams/1
# GET /teams/1.json
def show
#team = Team.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #team }
end
end
# GET /teams/new
# GET /teams/new.json
def new
#team = Team.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #team }
end
end
# GET /teams/1/edit
def edit
#team = Team.find(params[:id])
end
# POST /teams
# POST /teams.json
def create
raise params.to_yaml
#team = Team.new(params[:team])
respond_to do |format|
if #team.save
#team_member = TeamMember.new(:team_id => #team.id, :member_id => current_member.id,
:accepted => true, :leader => true, :joined => Time.now)
if #team_member.save
format.html { redirect_to team_path(#team), notice: 'Team was successfully created.' }
format.json { render json: #team, status: :created, location: #team }
else
#team.destroy
format.html { render action: "new" }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
else
format.html { render action: "new" }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
# PUT /teams/1
# PUT /teams/1.json
def update
#team = Team.find(params[:id])
respond_to do |format|
if #team.update_attributes(params[:team])
format.html { redirect_to #team, notice: 'Team was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
# DELETE /teams/1
# DELETE /teams/1.json
def destroy
#team = Team.find(params[:id])
#team.destroy
respond_to do |format|
format.html { redirect_to teams_url }
format.json { head :no_content }
end
end
end
team.rb model:
class Team < ActiveRecord::Base
attr_accessible :name, :email, :language, :link, :logo, :team_leader
validates_presence_of :name
validates_presence_of :email
validates_presence_of :language
validates_uniqueness_of :name
has_many :leaders, :class_name => "TeamMember", :conditions => { :leader => true }
has_many :members, :through => :team_members
has_many :team_members, :conditions => { :accepted => true, :active => true }
has_attached_file :logo,
:styles => { :medium => "320x180>", :thumb => "100x100>" },
:url => "/assets/teams/:id/:style/:basename.:extension",
:path => ":rails_root/public/assets/teams/:id/:style/:basename.:extension"
end

Resources