I'm writing a recipe rails api with my database being Mongodb. I am having trouble creating POSTING a JSON post that models a recipe for example:
{
"recipe": {
"name" : "Chicken",
"serving" : "3",
"macro" : {
"protein": "3",
"carb": "10",
"fat" : "5"
},
"user_id" : "587d5dccb3e9664e280a1199",
"ingredients" : [{
"name" : "Chicken Breast",
"value" : "3.123"
}]
}
}
Ingredients is a has_many relation, and i am embedding using accepts_nested_attributes_for. It is wanting the _id of ingredients before it has been created. Its giving me this error when posting:
"#<NoMethodError: undefined method `_id' for {\"name\"=>\"Chicken Breast\", \"value\"=>\"3.123\"}:ActiveSupport::HashWithIndifferentAccess>"
Here are my models for my app:
Recipe Model:
class Recipe
include Mongoid::Document
field :name, type: String
field :serving, type: Integer
embeds_one :macro # Stores object id of macro model in recipe
has_many :ingredients, inverse_of: :recipe #Stores object id of ingredient model in an array
# has_one :preperation # Properation steps are stored as an array so one to one relationship is needed
belongs_to :user # Recipe has one user that posted a recipe
accepts_nested_attributes_for :macro
accepts_nested_attributes_for :ingredients
validates :name, :serving, presence: true
end
Macro Model:
class Macro
include Mongoid::Document
field :protein, type: Integer
field :carb, type: Integer
field :fat, type: Integer
embedded_in :recipe
validates :protein, :carb, :fat, presence: true
end
Ingredient Model:
class Ingredient
include Mongoid::Document
field :name, type: String
field :value, type: String
belongs_to :recipe, inverse_of: :ingredients
validates :name, :value, presence: true
end
This is my controller for recipes:
class Api::V1::RecipeController < ApiController
def index
#recipes = Recipe.all
render json: #recipes
end
def create
#recipe = Recipe.new(recipe_params)
if #recipe.save
render json: #recipe
else
render :json => { :errors => #recipe.errors }, :status => 422
end
end
def show
#recipe = Recipe.find(params[:id])
render json: #recipe
end
def destroy
#recipe = Recipe.find(params[:id])
#recipe.destroy
render :nothing, status: :no_content
end
private
def recipe_params
params.require(:recipe).permit(:name, :serving, :user_id, macro: [:protein, :carb, :fat], ingredients: [:name, :value])
end
end
I cant figure out why its giving me the error when posting. Thanks for some help!
Related
I have a model job and a model user, the both can choose contracts types (that's why i use polymorphic).
I created a model contract for each contracts and i create an attached_contract model too.
Job model
class Job < ApplicationRecord
has_many :contracts, through: :attached_contracts
has_many :attached_contracts, as: :contractable, dependent: :destroy
accepts_nested_attributes_for :attached_contracts, reject_if: :all_blank, allow_destroy: true
end
AttachedContract model
class AttachedContract < ApplicationRecord
belongs_to :contract
belongs_to :contractable, polymorphic: true
validates :contract, uniqueness: { scope: [:contractable_type,:contractable_id] }
end
Contract model
class Contract < ApplicationRecord
validates :name, presence: true, allow_blank: false
has_many :attached_contracts
end
Jobs_controller
def new
#job = Job.new
#job.attached_contracts.build
end
def create
#job = current_company.jobs.build(set_params)
if #job.save
redirect_to job_path(#job)
end
else
render :new
end
end
def set_params
params.require(:job).permit(:title, :description, :address, attached_contracts_attributes: [:id, :contract_id, :_destroy]
end
In my view :
<%= simple_form_for([:company, #job]) do |f| %>
<div class="nested-fields">
<%= f.association :contracts, as: :check_boxes %>
</div>
<% end %>
When I submit my form my model AttachedContract still empty, and the data are lost.
I try tu put a "raise" in my controller after #job = current_company.jobs.build(set_params)
and I have a empty array if I call #job.attached_contracts
I don't understand beause in the "Request parameters" (rails debug console) I have the values : "contract_ids"=>["", "1", "3"]
Any idea ? May be the problem is in the polymorphic implantation ?
Finally, I changed the requested parameters by "contract_ids: [ ]" and that's work perfectly !
I have three models as follows :
#Product Model
class Product < ActiveRecord::Base
belongs_to :user
has_one :address
validates :title, :description, :user_id, presence: true
validates :product_type, numericality:{:greater_than => 0, :less_than_or_equal_to => 2}, presence: true
accepts_nested_attributes_for :address
end
#Address Model
class Address < ActiveRecord::Base
belongs_to :city
belongs_to :product
def related_city
city = address.city
end
end
#City Model
class City < ActiveRecord::Base
has_many :addresses
end
I am fetching a Product but I need to include associative attributes as well in my JSON response except few attributes.
Here is what I have done so far :
def show
product = Product.find(params[:id])
render json: product.to_json(:include => { :address => {
:include => { :city => {
:only => :name } },
},:user =>{:only=>{:first_name}}}), status: 200
end
This is giving me a syntax error. If I remove the user it is working fine but I need user's name as well in response. Moreover how would I write the above code using ruby's new hash syntax?
You can solve that problem using this gem: Active Model Serializers. It will let you create serializers for each model and use them to render the formatted JSON as you want. Take a look and let me know.
The problem is on the fifth line of your show method you have a comma surrounded by curly braces. Here is the hash sans comma, in the new syntax:
def show
product = Product.find(params[:id])
render json: product.to_json(include: { address: {
include: { city: {
only: :name }}}},
user: {only:{:first_name}}), status:200
end
I have a embedded model, Document in the embedded model can only be created by the admin, but users can select in form the value that they want
class User
include Mongoid::Document
embeds_one :state_model, class_name: "state_model", cascade_callbacks: true
accepts_nested_attributes_for :state_model
attr_accessor :current_password, :job_title_str, :state_model_id
convert_id_to_object :state_model_id, :state_model
end
class UsersController << ApplicationController
def update_params
params.require(:user).permit(:state_model_id)
end
end
module ConvertIdToObject
extend ActiveSupport::Concern
module ClassMethods
def convert_id_to_object(id, object)
id, object = id, object
if StateModel.by_id(id).present?
object = StateModel.by_id(id)
else
end
end
end
end
class StateModel
include Mongoid::Document
field :name, type: String, localize: true
field :value, type: String
scope :by_value, -> (value){ where({:value => value}) unless value == ''}
scope :by_id, -> (id){ where({:id => id}) unless id == ''}
embedded_in :user
validates :name, presence: true, uniqueness: true
validates :value, presence: true, uniqueness: true
end
= simple_form_for user do |f|
= f.input :state_model_id , collection: state_collection
= f.button :submit
Post:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"3/pmSUHrKRx56ycbraKYL+mEuAiS9QlwWt/bTglgsio=",
"user"=>{"state_model_id"=>"5612cb074d6f722582050000"},
"commit"=>"Update User",
"id"=>"bowtch"}
End I have a Notimplemented error raised by my usercontroller Like if don't accept state_model_id as a param ... I'm stuck here ...
I've a Rails API and I've two models:
class Event < ActiveRecord::Base
belongs_to :category
has_many :event_categories
has_many :events, through: :event_categories
attr_accessible :title, :description, :event_categories_attributes
accepts_nested_attributes_for :event_categories
end
and
class EventCategory < ActiveRecord::Base
belongs_to :event
belongs_to :category
attr_accessible :category_id, :event_id, :principal
validates :event, :presence => true
validates :category, :presence => true
validates_uniqueness_of :event_id, :scope => :category_id
end
In a first moment, EventCategory didn't exist so I created Event resources sending params like event[title]='event1', event[description] = 'blablbla' thought POST REST request.
My API EventsController was like this (I haven't a new method because I don't need views):
def create
#event = Event.create(params[:event])
if #event
respond_with #event
else
respond_with nil, location: nil, status: 404
end
end
This way worked correctly for me. Now, with the new EventCategory model I don't know how I could create EventCategories models at the same time.
I've trying this... but it doesn't work:
def create
#event = Event.new(params[:event])
#event.event_categories.build
if #event.save
respond_with #event
else
respond_with nil, location: nil, status: 404
end
end
Rails told me:
{
"event_categories.event": [
"can't be blank"
],
"event_categories.category": [
"can't be blank"
]
}
I send the category_id like this:
event[event_categories_attributes][0][category_id] = 2
Any ideas?
In your create action, instead of this:
#event.event_categories.build
Try this:
#event.event_categories = EventCategory.new do |ec|
ec.event = #event
ec.category = the_cattegory_you_want_to_specify
# You need both of these as you are validating the presence of event AND category
end
I am new to Ruby and Rails. I'm try to create a "Team" object that has a leader id and an array of users attached.
Problems
I am unable to attach the array of users to the team object
I am unable to define leader object, only store its id
Any help greatly appreciated
My Rails Models:
class Team
include Mongoid::Document
include Mongoid::Timestamps::Created
include Mongoid::Timestamps::Created
field :name
field :slug
field :description
field :leader
field :users, type: Array
field :holiday_days_per_year, type: Integer
field :hours_per_day, type: Integer
field :organisation_id, type: Integer
embeds_many :users
validates :name, :holiday_days_per_year, :presence => true
validates :holiday_days_per_year, :hours_per_day, :numericality => true
before_save :set_slug
def set_slug
self.slug = "#{name.parameterize}"
end
end
class User
include Mongoid::Document
include Mongoid::Timestamps::Created
include Mongoid::Timestamps::Created
field :slug
field :first_name
field :last_name
field :birth_date, type: Date
field :job_title
field :job_start_date, type: Date
field :job_probation_ends, type: Date
field :work_email
field :work_address
field :work_phone_number
field :personal_email
field :personal_address
field :personal_phone_number
field :organisation_id, type: Integer
# emails should be unique
validates_uniqueness_of :work_email, :personal_email
validates :first_name, :last_name, :birth_date,
:job_title, :job_start_date, :job_probation_ends,
:work_address, :work_phone_number,
:personal_address, :personal_phone_number,
:presence => true
# validates emails
validates_format_of :work_email, :personal_email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
belongs_to :team, :inverse_of => :users
before_save :set_slug
def set_slug
self.slug = "#{first_name.parameterize}-#{last_name.parameterize}"
end
end
controller action
# POST /teams
# POST /teams.json
def create
new_params = params.permit(
:name, :holiday_days_per_year, :hours_per_day, :leader, :users)
#team = Team.new(new_params)
if #team.save
render json: #team, status: :created, location: #team
else
render json: #team.errors, status: :unprocessable_entity
end
end
JSON Sent
{
holiday_days_per_year: 20
hours_per_day: 8
leader: "522cf27114bc38307a000004"
name: "Tester"
users: [
0: "522cf27114bc38307a000004"
1: "522d966214bc38659300000d"
2: "522dd21214bc38ac6b000011"
]
}
The object is created, but users and leader dont get saved, the object comes back as
{
_id: "522df8c714bc38ef3e000022",
created_at: "2013-09-09T16:35:19.405Z",
description: null,
holiday_days_per_year: 20,
hours_per_day: 8,
leader: "522d966214bc38659300000d",
name: "Tester",
organisation_id: null,
slug: "tester",
users: [ ]
}
In your model, redefine your "as_json" method with the following
class Team < ActiveRecord::Base
..
has_many :users
def as_json(options)
{ :name=>self.name, :leader=>self.leader, :users=>self.users }
end
end