#RubyOnRails Many to Many relationship not inserting into join table - ruby-on-rails

I'm creating an app while learning how to code in Ruby. I'm making a simple league app where i can create new teams, players, leagues...
I have a team model and a league model and because a team can enter in more than one league and one league can have more than one team they are a many to many association. However, when i create / edit a team it doesnt insert anything into the join table, only changes the other attributes.
The models:
Team Model
class Team < ActiveRecord::Base
validates_presence_of :name
has_many :teams_join_leagues, :dependent => :destroy
has_many :leagues, through: :teams_join_leagues
end
League Model
class League < ActiveRecord::Base
validates_presence_of :name, :begindate, :enddate, :prizepool, :season_id
validate :start_must_be_before_end_time
has_many :teams_join_leagues, :dependent => :destroy
has_many :teams, through: :teams_join_leagues
Join TeamLeague Model
class TeamsJoinLeague < ActiveRecord::Base
belongs_to :team
belongs_to :league
end
TeamController param function:
def team_params
params.require(:team).permit(:name, leagues: [:id])
end
Create function:
def create
#team = Team.new(team_params)
respond_to do |format|
if #team.save
format.html { redirect_to #team, notice: 'Team was successfully created.' }
format.json { render :show, status: :created, location: #team }
else
format.html { render :new }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
What i'm doing wrong? it never inserts anything on the join table leaving all the teams without leagues :/

Im assuming your teams_join_leagues table like this:
create_table "teams_join_leagues", force: :cascade do |t|
t.integer "team_id"
t.integer "league_id"
....
end
so in your create team, it should look like this or similar
def create
#league = current_team.teams_join_leagues.build(league_id: params[:league_id])
if #league.save
....
end

Related

3rd level nested model not receiving grandparent ID in form

I have a 3 models. User, CV, and Language. A User has one CV. A CV has many Languages. The User has many Languages through its CV. When I try to save the form I get an error that the Language does not have a User ID. How can I get the User ID to pass through the CV and to the Language in my form?
The CV is receiving the User ID properly. Languages is not.
I am using the Simple-Form and Cocoon gems.
Simplified version of form
= simple_form_for(#cv, url: user_cvs_path) do |f|
= f.simple_fields_for :languages do |language|
From User Model
has_one :cv, dependent: :destroy
has_many :languages, through: :cv, inverse_of: :user
From Cv Model
belongs_to :user
has_many :languages, dependent: :destroy
accepts_nested_attributes_for :languages, allow_destroy: true
From Language Model
belongs_to :user
belongs_to :cv
From the CV Controller
before_action :set_user
def new
#cv = #user.build_cv
#cv.languages.build
end
def create
#cv = #user.create_cv(cv_params)
respond_to do |format|
if #cv.save
format.html { redirect_to user_cv_url(#user, #cv), notice: 'Cv was successfully created.' }
format.json { render :show, status: :created, location: #cv }
else
format.html { render :new }
format.json { render json: #cv.errors, status: :unprocessable_entity }
end
end
end
def cv_params
params.require(:cv).permit(
:user_id,
:first_name,
:middle_name,
:last_name,
... # lots of params left out for brevity
languages_attributes: [
:id,
:cv_id,
:user_id,
:name,
:read,
:write,
:speak,
:listen,
:_destroy])
end
def set_user
#user = current_user if user_signed_in?
end
Your Language model does not need the belongs_to :user. Language belongs to CV and CV belongs to User, so the relation between Language and User is already in place. If you need to access the user for a specific language you can write #language.cv.user
To solve your problem just remove the belongs_to :user from the Language model, remove the user_id from languages_attributes, and remove the user_id from languages table.

rails : association tabel (has_and_belongs_to_many) not save any record

i use rails 5 , simple form. in my app there is a Category model and there is a OnlineProduct model. i dont know why when i want to add some categories to my OnlineProduct association table remain empty and don't change.
Category model:
class Category < ApplicationRecord
has_ancestry
has_and_belongs_to_many :internet_products
end
InternetProduct model:
class InternetProduct < ApplicationRecord
belongs_to :user
belongs_to :business
has_and_belongs_to_many :categories
end
InternetProduct controller:
def new
#internet_product = InternetProduct.new
end
def create
#internet_product = InternetProduct.new(internet_product_params)
respond_to do |format|
if #internet_product.save
format.html { redirect_to #internet_product, notice: 'Internet product was successfully created.' }
format.json { render :show, status: :created, location: #internet_product }
else
format.html { render :new }
format.json { render json: #internet_product.errors, status: :unprocessable_entity }
end
end
end
private:
def internet_product_params
params.require(:internet_product).permit(:name, :description, :mainpic, :terms_of_use,
:real_price, :price_discount, :percent_discount,
:start_date, :expire_date, :couponـlimitation, :slung,
:title, :meta_data, :meta_keyword, :enability, :status,
:like, :free_delivery, :garanty, :waranty, :money_back,
:user_id, :business_id,
categoriesـattributes: [:id, :title])
end
and in the view only the part of who relate to categories :
<%= f.association :categories %>
all the categories list in view (form) but when i select some of them not save in database. in rails console i do this
p = InternetProduct.find(5)
p.categories = Category.find(1,2,3)
this save to database without any problem, what should i do ?
tanks for reading this
I found solution to solve this. when we use has_and_belong_to_many or any other relation , if you want to use collection select in simple_form , in the model also should be add this command for nesting form
accepts_nested_attributes_for :categories
also in the controller in related method for example in the new we should
def new
#internet_product = InternetProduct.new
#internet_product.categories.build
end

Create a post with many-to-many relationship in Ruby on Rails

I have a structure very much for between category and yell. What I do is qeuro a call on POST type API with the following parameters:
{
"user_id":"1",
"title":"primeito",
"desciption":"de_novo",
"categories":[{"name":"eletro"},{"name":"domestic"},{"name":"new_category"}],
"yell_type":"novo",
"price":"10,00",
"payment_type":"boleto"
}
My structure is as follows:
My model yell:
#yell.rb
class Yell < ActiveRecord::Base
belongs_to :user, inverse_of: :yells
has_and_belongs_to_many :categories
end
model category:
#category.rb
class Category < ActiveRecord::Base
has_and_belongs_to_many :yells
end
method crete in controller yell:
#yells_controller.rb
def create
#yell = Yell.new(yell_params)
params[:categories].each do |rel|
#category = Category.find_by_name(rel[:name])
if #category
#only creates the relationship
else
#yell.categories.build(name: rel[:name]) #creates the relationship and category
end
end
if #yell.save
render json: #yell, status: :created, location: api_yell_path(#yell)
else
render json: #yell.errors, status: :unprocessable_entity
end
end
...
private:
def yell_params
params.require(:yell).permit(:title, :desciption, :price, :payment_type, :user_id, :yell_type, :categories)
end
So I created the table
class CreateCategoriesYellsJoinTable < ActiveRecord::Migration
def self.up
create_table :categories_yells, :id => false do |t|
t.integer :category_id
t.integer :yell_id
end
add_index :categories_yells, [:category_id, :yell_id]
end
def self.down
drop_table :categories_yells
end
end
I can make him create the categories, but does not know how to create only the relationship. Agluem can help me is the comment #only creates the relationship?
I need to do this check because the category name is unique
Also if someone know something more elegant way to do this, I accept suggestions
I am not quite sure I understood the last paragraph, but I think you need an intermediate table to join the two models first.
You would need to create a table like this:
class CreateCategoriesAndYells < ActiveRecord::Migration
def change
create_table :categories_yells, id: false do |t|
t.belongs_to :category, index: true
t.belongs_to :yell, index: true
end
end
end
Then you would need to update your controller to say something like this:
#yell.categories.build(category_params)
You would need also to pass the category parameters to the controller.
In order to do so I had to create a model to join my table:
model category_yell.rb
class CategoriesYell < ActiveRecord::Base
belongs_to :category
belongs_to :yell
end
and create my method was as follows:
def create
##yell = Yell.new(yell_params.except(:categories))
#yell = Yell.new({title: params[:title], desciption: params[:desciption], price: params[:price], user_id: params[:user_id], yell_type: params[:yell_type]})
if #yell.save
Array(params[:categories]).each do |rel|
#category = Category.find_by_name(rel[:name])
if #category
#categories_yells = CategoriesYell.new(category_id: #category.id, yell_id: #yell.id)
if #categories_yells.save
#yell.categories.build(id: #category.id, name: rel[:name])#only creates the relationship
else
render json: {status: 1, message:"relationship categoy not create", data: #yell.errors}, status: :unprocessable_entity
end
else
#yell.categories.create(name: rel[:name]) #creates the relationship and category
end
end
render json: {status: 0, message:"sucess", data: #yell}, status: :created
else
render json: {status: -1, message:"error", data: #yell.errors}, status: :unprocessable_entity
end
end

How to use first_or_create to update existing contacts in rails 4 if they exist?

I'm creating an app where users can create embeddable forms that collect contacts for them (email subscribers).
When the user gets a new email subscriber, a new contact is created with the email address, and the contact is associated with the user and the form it was create through.
However right now if the same email gets entered twice, it creates a new contact, instead of updating an existing contact associated with the user.
In my Contacts controller, I'm trying to use the first_or_create function to check if the user already has a contact with that email address, before creating a new one.
def create
#user = #form.user
#contact = Contact.where(:user_id => #user, :email => :email).first_or_create(contact_params)
#contact.user = current_user
respond_to do |format|
if #contact.save
format.html { redirect_to :back, notice: 'New contact created!' }
format.json { render :show, status: :created, location: #contacts }
else
format.html { render :new }
format.json { render json: #contact.errors, status: :unprocessable_entity }
end
end
end
While this doesn't return an error when creating a contact, it still creates a duplicate contact.
How do I properly do this?
NOTES: As you can see, I'm also trying to pass contact_params, which includes important information like the contacts name, etc.
Here's the models for reference...
class User < ActiveRecord::Base
has_many :forms, :dependent => :destroy
has_many :contacts, :dependent => :destroy
end
class Contact < ActiveRecord::Base
belongs_to :user
belongs_to :contactable, polymorphic: true
end
class Form < ActiveRecord::Base
belongs_to :user
has_many :contacts, as: :contactable
end
Thanks for any help.
When creating your contacts table you should pass the unique: true parameter. So it should be ...t.string :email, unique: true...instead of just t.string :email
In your contact model, put
validates :email, uniqueness: { scope: :user_id }
If you try to create another contact with the same email, validations will fail and a new contact won't be created.

Has And Belongs to Many Through Save and Update

Here are my models:
class Examination < ActiveRecord::Base
has_many :categorizations
has_many :exam_statuses, :through => :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :examination
belongs_to :exam_status
end
class ExamStatus < ActiveRecord::Base
has_many :categorizations
has_many :examinations, :through => :categorizations
end
I can assign relations from the console without any problem by typing;
e = Examination.first
e.exam_status_ids = [1,2]
And also in the examinations/index.html.erb file I can list exam_statuses without any problem.
The problem is, I can't update or create any exam_status relations from examinations/_form.html.erb file!
I'm trying to make this with simple_form:
<%= f.association :exam_statuses, as: :check_boxes, label: 'Sınavın Durumu' %>
Its listing all the statuses with checkboxes but not updating them.
Logs saying:
"Unpermitted parameters: exam_status_ids"
And finally my controller, which is generated by "scaffold" by default, for update is:
def update
respond_to do |format|
if #examination.update(examination_params)
format.html { redirect_to #examination, notice: 'Examination was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #examination.errors, status: :unprocessable_entity }
end
end
end
From what your logs say, you should permit the parameter, in the controller:
def examination_params
params.require(:examination).permit(:exam_status_ids)
end
Don't forget to add other parameters in the permit call!
Then you can use it in your controller's action:
def update
...
#examination.update_attributes! examination_params
...
end
I think you need to use accepts_nested_attributes in this case to get it updated.
For more details you can refer this article

Resources