Rails: Nested Models Not Saving Association - ruby-on-rails

I have two models, Trips and Locations. A trip has a origin and a destination which are both references to Location:
class Trip < ActiveRecord::Base
attr_accessible :name, :destination, :origin, :start_datetime, :transportation, :trip_type, :destination_attributes, :origin_attributes
enum_attr :trip_type, %w(Hitchhiker Driver)
has_one :origin, :class_name => 'Location' , :primary_key => :origin, :foreign_key => :id
has_one :destination, :class_name => 'Location' , :primary_key => :destination, :foreign_key => :id
accepts_nested_attributes_for :origin, :allow_destroy => true
accepts_nested_attributes_for :destination, :allow_destroy => true
belongs_to :user
validates_presence_of :name, :destination, :origin, :start_datetime, :transportation, :trip_type
end
class Location < ActiveRecord::Base
attr_accessible :address, :latitude, :longitude
geocoded_by :address
before_validation :geocode
validates_presence_of :address
validate :geocoding_was_found
def geocoding_was_found
errors.add(:address, 'is not valid') if latitude.nil? || longitude.nil?
end
end
When calling create in the controller, it saves all of the records (two location records and the trips record) but does not save the association.
def create
#trip = Trip.new(params[:trip])
#trip.user = current_user
respond_to do |format|
if #trip.save
format.html { redirect_to #trip, notice: 'Trip was successfully created.' }
format.json { render json: #trip, status: :created, location: #trip }
else
format.html { render action: "new" }
format.json { render json: #trip.errors, status: :unprocessable_entity }
end
end
end
I am using nested forms so the data for location is being passed in through origin_attributes and destination_attributes. My guess is it is because the two fields are called origin and destination instead of _id.

Related

rails nested_attributes form can't find id

So i have two models : Internship and Review. I want the Review to be a nested_attributs of Internship. So that i can create an internship with a review.
My problem is that the review form integrated in the new form internship, doesn't find the id of the internship. It raise the errors 'Review internship must exist'
Internship.rb
has_many :reviews, foreign_key: "review_internship_id"
has_many :review_users, foreign_key: 'review_user_id', class_name:"User", through: :reviews
accepts_nested_attributes_for :reviews, allow_destroy: true
validates_associated :reviews
Review.rb
belongs_to :review_user, class_name: "User"
belongs_to :review_internship, class_name: "Internship"
Internship_controller
def new
#internship = Internship.new
#internship.reviews.new
end
def create
#internship = Internship.new(internship_params)
#internship.user = current_user
#internship.reviews.first.review_user_id = current_user.id
respond_to do |format|
if #internship.save
format.html { redirect_to #internship, notice: 'Expérience crée avec succès' }
format.json { render :show, status: :created, location: #internship }
else
format.html { render :new }
format.json { render json: #internship.errors, status: :unprocessable_entity }
end
end
end
private
def internship_params
params.require(:internship).permit(:adress, :zipcode, :city, :specialty, :organization, :population, :cursus, :title, :duration, :description, :region, :remuneration, :user_id, reviews_attributes: [:title, :notation, :description, review_internship_id: params[:internship_id], review_user_id: current_user.id])
end
The new form in internship new
<%= form_with(model: internship, local: true) do |form| %>
....
<!--NESTED ATTRIBUTS REVIEW-->
<%= form.fields_for :reviews do |p| %>
<%= p.label :titre %>
<%= p.text_field :title, class:"form-control" %>
<%= p.label :note %>
<%= p.number_field :notation, min: 1, max: 5, class:"form-control" %>
<%= p.label :description %>
<%= p.text_area :description, class:"form-control" %>
<% end %>
...
<% end %>
So this is what i've tried in Internship controller
#intership.reviews.review_internship_id = #internship.id
So that it can find the id of the internship. The error is "Review Internship must exist".
It did the same with "Review User", which was solved with #internship.reviews.first.review_user_id = current_user.id
Do you have any idea where the problem is, and how i can find the internship id with another way. I've also tried the params[:id]
Thanks for your help
:
You don't really need a user_id foreign key on reviews since it can get there through the interview:
class Review
belongs_to :internship
has_one :user, through: :interview
end
class Internship
belongs_to :user
has_many :reviews
end
class User
has_many :internships
has_many :reviews, through: :internships
end
And you definitely don't ever need to be manually assigning parent ids for nested records.
class IntershipsController < ApplicationController
def new
#internship = Internship.new
#internship.reviews.new
end
def create
#internship = Internship.new(internship_params) do |i|
i.user = current_user
end
respond_to do |format|
if #internship.save
format.html { redirect_to #internship, notice: 'Expérience crée avec succès' }
format.json { render :show, status: :created, location: #internship }
else
format.html { render :new }
format.json { render json: #internship.errors, status: :unprocessable_entity }
end
end
end
private
def internship_params
# use some line-breaks!
params.require(:internship)
.permit(
:adress, :zipcode, :city, :specialty,
:organization, :population, :cursus,
:title, :duration, :description,
:region, :remuneration, :user_id,
reviews_attributes: [
:id, :title, :notation, :description
]
)
end
end

Rails 4- Complex model validation (has_many, through)

I am trying to validate the "name" attribute in my Ingredient model. However, when I add validates :name, :uniqueness => true in my Ingredient model, it does not validate the name (can insert ingredient with same name). The ingredient model has a complex relationship with other model. Please see the code below.
My ultimate goal is to allows user to create ingredient if the ingredient does not exist in the Ingredient table. If the ingredient already existed, used the ingredient id for quantity. If anyone has any idea how to achieve that, please provide the solution to it. Thanks in advance.
ingredient.rb
class Ingredient < ActiveRecord::Base
has_many :quantities
has_many :recipes, through: :quantities
validates :name, :presence => true, :uniqueness => true
end
quantity.rb
class Quantity < ActiveRecord::Base
belongs_to :ingredient
belongs_to :recipe
accepts_nested_attributes_for :ingredient,
:reject_if => :all_blank
validates :ingredient, :uniqueness => true
end
recipe.rb
class Recipe < ActiveRecord::Base
has_many :quantities,
dependent: :destroy
has_many :ingredients,
:through => :quantities
accepts_nested_attributes_for :quantities,
reject_if: :all_blank,
allow_destroy: true
accepts_nested_attributes_for :ingredients
end
view section for creating Ingredient:
%strong Ingredients:
%fieldset#recipe-ingredients
%br
= f.fields_for :quantities do |builder|
= render 'recipe/quantity_fields', f: builder
.links
= link_to_add_association 'add ingredient', f, :quantities, 'data-association-insertion-node' => '#recipe-ingredients', 'data-assoication-insertion-moethod' => "append", :wrap_object => Proc.new{|quantity| quantity.ingredient.build ; quantity}
%br
Ingredient controller:
class IngredientController < ApplicationController
before_action :set_ingredient, only: [:show, :edit, :update, :destroy]
# GET /ingredients
# GET /ingredients.json
def index
#ingredients = Ingredient.all
end
# GET /ingredients/1
# GET /ingredients/1.json
def show
end
# GET /ingredients/new
def new
#ingredient = Ingredient.new
end
# GET /ingredients/1/edit
def edit
end
def create
#ingredient = Ingredient.new(ingredient_params)
respond_to do |format|
if #ingredient.save
format.html { redirect_to #ingredient, notice: 'Ingredient was successfully created.' }
format.json { render :show, status: :created, location: #ingredient }
else
format.html { render :new }
format.json { render json: #ingredient.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /ingredients/1
# PATCH/PUT /ingredients/1.json
def update
respond_to do |format|
if #ingredient.update(ingredient_params)
format.html { redirect_to #ingredient, notice: 'Ingredient was successfully updated.' }
format.json { render :show, status: :ok, location: #ingredient }
else
format.html { render :edit }
format.json { render json: #ingredient.errors, status: :unprocessable_entity }
end
end
end
# DELETE /ingredients/1
# DELETE /ingredients/1.json
def destroy
#ingredient.destroy
respond_to do |format|
format.html { redirect_to ingredients_url, notice: 'Ingredient was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ingredient
#ingredient = Ingredient.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def ingredient_params
params.require(:ingredient).permit(:name)
end
end
It seems like a known issue probably a bug. Check this: https://github.com/rails/rails/issues/20676

creating an object with has_many association results in item can not be blank

I have following associations and the related controller, in my form I am adding every field as it should be. But I still get an error Ratings item can't be blank when I try to create an Item. I am using Rails 4.0 . I did searched extensively for this but could not still find what I am doing wrong. Thankyou!
class Item < ActiveRecord::Base
has_many :ratings, dependent: :destroy
accepts_nested_attributes_for :ratings, :allow_destroy => true
validates :name , :length => { minimum: 3 }
validates :category , :length => { minimum: 3 }
end
class Ratings < ActiveRecord::Base
belongs_to :user
belongs_to :item
default_scope -> { order('created_at DESC') }
validates :user_id, :presence => true
validates :item_id, :presence => true
validates_numericality_of :rating, :greater_than_or_equal_to => 0
validates_numericality_of :rating, :less_than_or_equal_to => 5
end
class ItemsController < ApplicationController
before_action :set_item, only: [:show]
before_action :user_signed_in?, only: :create
def create
#item = Item.new
#rating = #item.ratings.build
#rating.comment = params[:item][:ratings_attributes][:comment]
#rating.rating = params[:item][:ratings_attributes][:rating]
#rating.user_id = current_user.id
#item.name = params[:item][:name]
#item.url = params[:item][:url]
#item.full_address = params[:item][:full_address]
#item.city = params[:item][:city]
#item.country = params[:item][:country]
#item.category = params[:item][:category]
respond_to do |format|
if #item.save
#TODO create rating here (First rating of an Item)
flash[:success] = "Welcome to inmyopnion"
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render action: 'show', status: :created, location: #item }
else
format.html { render action: 'new' }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
def new
#item = Item.new
end
def show
end
def destroy
end
private
def set_item
#item = Item.find(params[:id])
end
def item_params
params.require(:item).permit(:name, :url, :full_address, :city, :country, :category, :ratings_attributes => [:rating, :comment])
end
def user_signed_in?
#TODO: should display should sign in to rate an item
redirect_to(root_url) unless signed_in?
end
end
Simplify your controller! Since you are allowing nested_attributes this should be sufficient:
#item = Item.create(params[:item])
The problem might be caused by #rating object not being saved.
I got it working by commenting the below given line in
class Ratings < ActiveRecord::Base
validates :item_id, :presence => true
but my association rspec test fails and saves a Ratings without an item_id.
Rest of the code is similar to what I posted as
#item = Item.create(params[:item])
gives ActiveModel::ForbiddenAttributesError
Alright much playing with the code and docs of nested_attributes finally a working program that validates association too. These are the changes (marked in between ** .... **) listed below
class Item < ActiveRecord::Base
has_many :ratings, dependent: :destroy, **inverse_of: :item**
accepts_nested_attributes_for :ratings, :allow_destroy => true
validates :name , :length => { minimum: 3 }
validates :category , :length => { minimum: 3 }
end
class Ratings < ActiveRecord::Base
belongs_to :user
belongs_to :item, **inverse_of: :ratings**
default_scope -> { order('created_at DESC') }
validates :user_id, :presence => true
validates_presence_of :item
validates_numericality_of :rating, :greater_than_or_equal_to => 0
validates_numericality_of :rating, :less_than_or_equal_to => 5
end
Still not able to create one from #item = Item.create(params[:item]) which still gives an gives
ActiveModel::ForbiddenAttributesError as suggested by #BroiSatse and also the docs of nested_attributes that should not be the case
the problem might be in
class ItemsController < ApplicationController
def item_params
params.require(:item).permit(:name, :url, :full_address, :city, :country, :category, :ratings_attributes => [:rating, :comment])
end
will work on to resolve that too and post an answer if I find a solution.

ActiveRecord Error

I have two model class,
class Designation < ActiveRecord::Base
attr_accessible :name
validates :name, presence: true, uniqueness: { case_sensitive: false }
has_many :employee_details
accepts_nested_attributes_for :employee_details
end
and
class EmployeeDetail < ActiveRecord::Base
belongs_to :Designation
attr_accessible :bloodGroup, :dob, :doc, :doj, :empId, :name, :panNo, :status, :Designation
end
I have generated default scaffold for EmployeeDetail. from EmployeeDetail page when i tried to create and enter integer value in designation textbox, it gives me error
ActiveRecord::AssociationTypeMismatch in EmployeeDetailsController#create
Designation(#81846160) expected, got String(#75419260).
can anyone help me to sortout this problem?
EmployeeDetailController#create:-
def create
#employee_detail = EmployeeDetail.new(params[:employee_detail])
respond_to do |format|
if #employee_detail.save
format.html { redirect_to #employee_detail, notice: 'Employee detail was successfully created.' }
format.json { render json: #employee_detail, status: :created, location: #employee_detail }
else
format.html { render action: "new" }
format.json { render json: #employee_detail.errors, status: :unprocessable_entity }
end
end
end
When you associate any model, you should use the lowercase version of the model name.
Change:
belongs_to :Designation
to:
belongs_to :designation

ActiveRecord::AssociationTypeMismatch on many to many relaitonship

Hello I am trying to build a multi select to populate a many-to-many join table. I am able to crate the new newform but am getting "AssociationTypeMismatch" when I try to save my record.
The solutions that I am finding on the web are not solving my problem.
Hoping someone can resolve what I should be doing to get rid of "AssociationTypeMismatch"
class Presenter < ActiveRecord::Base
belongs_to :seminar
belongs_to :person
end
class Seminar < ActiveRecord::Base
attr_accessible :description, :title,
has_many :presenters, :foreign_key => "person_id"
has_many :lecturer, :through => :presenters, :source => :person
accepts_nested_attributes_for :lecturer, :presenters
end
class Person < ActiveRecord::Base
attr_accessible :first_name, :last_name
has_many :presentors
has_many :lecturingAt, :through => :presentors
def fullName
first_name + " " + last_name
end
end
seminars_controller.rb
def new
#seminar = Seminar.new
#current_presenters = Person.find(:all)
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #seminar }
end
end
....
def create
#seminar = Seminar.new(params[:seminar])
respond_to do |format|
if #seminar.save
format.html { redirect_to(#seminar, :notice => 'Seminar was successfully created.') }
format.xml { render :xml => #seminar, :status => :created, :location => #seminar }
else
format.html { render :action => "new" }
format.xml { render :xml => #seminar.errors, :status => :unprocessable_entity }
end
end
end
Seminars/_form.html.erb. has which populates my collection select with the names and persion ids of
possible lecurers.
....
<div class="field">
<%= f.label :presenter_id %><br />
<%= collection_select(:seminar,:lecturer,#current_presenters, :id, :fullName,{}, {:multiple=>true} ) %>
....
On submitting the params passed into my controller
Parameters: {...., "seminar"=>{ "lecturer"=>["1", "2"], "title"=>"1234567890", "description"=>"ASDFGHJKL:"}, "commit"=>"Create Seminar"}
Getting error:
ActiveRecord::AssociationTypeMismatch (Instructor(#86075540) expected, got String(#73495120)):.
#seminar = Seminar.new
Try this
#seminar.lecturer_ids = params[:seminar].delete(:lecturer)
#seminar.update_attributes(params[:seminar])

Resources