rails: Create does not work with :through in third model - ruby-on-rails

So I have a nested resource with
resources :albums do
resources :elements
end
I can update, delete and view those elements.
What I can not really do is to create a new element.
So it is actually created in the database but not in the mapping table.
Models:
class Album:
has_many :elements, :through => :albums_elements
has_many :albums_elements
class Element:
has_many :albums_elements
has_one :album, :through => :albums_elements
class AlbumsElement:
belongs_to :album
belongs_to :element
In the element Controller I have:
def create
#element = Element.new(params[:element])
#album = Album.find(params[:album_id])
respond_to do |format|
if #element.save
format.html { redirect_to album_elements_path(#album), :notice => 'Element was successfully created.' }
format.json { render :json => #element, :status => :created, :location => #element }
else
format.html { render :action => "new" }
format.json { render :json => #element.errors, :status => :unprocessable_entity }
end
end
end
So as I said, when I press the create button in the form, the element is being created correctly in the table "elements", but not inserted into "albums_elements".
I saw a similar post here, where the author was told to fix his dependencies.
But I don't see an error in mines?
How do I tell rails to insert into both tables?
elements AND albums_elements?

Would you please check by relating your #element and #album in elements_controller class? Like you already have
#element = Element.new(params[:element])
#album = Album.find(params[:album_id])
Just add
#element.album = #album
Now #element.save should insert a entry in your relationship table also.
Let me know if it works. I've just answered after a glance to the problem.
Clarifications:
I will try to make a sample app for you. But before that i need to know some more.
Seems the relationship between Album and Element is one-to-many, then why you are using has_many :through? It could be simply Album: has_many :products and Product: belongs_to :album.
If you must use a relationship table, does it have any other attributes?
Is it OK if I provide any solution of one-to-many?
I will try to provide you the best rails way to save these entries asap.
Thnx

Related

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 / Update Resources via Rails 5 API with association

I have a Match model with 2 players fields that have a belongs_to association with the User model
Model
class Match < ApplicationRecord
belongs_to :player1, :class_name => 'User', :foreign_key => 'player1'
belongs_to :player2, :class_name => 'User', :foreign_key => 'player2'
end
When creating a Match via the API (using a Postman POST request) I tried passing the user_id of the players but got a TypeMismatch error indicating the controller expected a User object but got a Fixnum.
Looking at this line:
#match = Match.new(match_params)
the error makes sense, so I modified my default scaffold generated controllers to look like this instead:
def create
#match = Match.new
#match.player1 = User.find(params[:match][:player1])
#match.player2 = User.find(params[:match][:player2])
if #match.save
render json: #match, status: :created, location: #match
else
render json: #match.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /matches/1
def update
if #match.update( :player1 => User.find(params[:match][:player1]),
:player2 => User.find(params[:match][:player2])
)
render json: #match
else
render json: #match.errors, status: :unprocessable_entity
end
end
It works, but the solution seems "inelegant".
Is there a better way to pass values to a controller with a belongs_to association?
Could you please try changing your foreign_key in Match model from player1, player2 to player1_id, player2_id respectively, via database migrations. Because your foreign_key and belongs_to associations are same? Please let me know whether it works!

Creating a join table record through two different controllers in rails

I'm trying to get my head around the best way to add a record to a join table through alternative controllers in rails.
I have various models in my app that will require this, but I'm focusing on these two first before I transcribe the method into others, so shall use this as the example. I have a Venue and Interest model which are to be connected through VenuesInterests model (it has a couple of extra optional attributes so isn't a HABTM relationship). A user can admin a Venue instance and/or an Interest instance and therefore there should be an ability to select Venues to attach to an Interest and likewise Interests to attach to a Venue. This should be done with an Add Venues link on the Interest instance view and an Add Interests link on the Venue instance view. This would then take the user to a list of the relevant instances for them to select ones they would like to select.
Here are my models:
Venue.rb
class Venue < ActiveRecord::Base
has_many :interests, through: :venue_interests
has_many :venues_interests, dependent: :destroy
accepts_nested_attributes_for :venues_interests, :allow_destroy => true
end
Interest.rb
class Interest < ActiveRecord::Base
has_many :venues, through: :venue_interests
has_many :venues_interests, dependent: :destroy
end
VenuesInterests.rb
class VenuesInterest < ActiveRecord::Base
belongs_to :interest
belongs_to :venue
validates :interest_id, presence: true
validates :venue_id, presence: true
end
This all seems fine, however it's the controller and views that I'm struggling with. I've tried adding an extra method add_interest to the Venues controller to do the job of the create method in the VenuesInterests controller, so that there will be a different view when adding Venues to an Interest than there would be adding Interests to a Venue, otherwise I don't know how I would do this. My current Venues controller is as follows:
VenuesController.rb:
class VenuesController < ApplicationController
before_filter :authenticate_knocker!, only: [:new, :edit, :create, :update, :destroy]
respond_to :html, :json
def index
#venues = Venue.all.paginate(page: params[:page]).order('created_at DESC')
end
def show
#venue = Venue.find(params[:id])
#hash = Gmaps4rails.build_markers(#venue) do |venue, marker|
marker.lat venue.latitude
marker.lng venue.longitude
marker.infowindow venue.name
end
end
def new
#venue = Venue.new
end
def edit
#venue = Venue.find(params[:id])
end
def create
#venue = current_knocker.venues.create(venue_params)
respond_to do |format|
if #venue.save!
format.html { redirect_to #venue, notice: 'Venue was successfully created.' }
format.json { render json: #venue, status: :created, location: #venue }
else
format.html { render action: "new" }
format.json { render json: #venue.errors, status: :unprocessable_entity }
end
end
end
def update
#venue = Venue.find(params[:id])
#venue.update_attributes(venue_params)
respond_to do |format|
if #venue.update_attributes(venue_params)
format.html { redirect_to(#venue, :notice => 'Your Venue was successfully updated.') }
format.json { respond_with_bip(#venue) }
else
format.html { render :action => "edit" }
format.json { respond_with_bip(#venue) }
end
end
end
def destroy
end
def add_interests
#venues_interests = VenuesInterest.new
#interests = Interests.all.paginate(page: params[:page]).order(:name)
end
private
def venue_params
params.require(:venue).permit(:admin... etc)
end
end
This isn't currently working as I'm not sure how to reference other classes within a controller, but the important thing I'd like to know is is there a better way to do this or am I (kind of) on the right track? If anyone has a good method (perhaps a jQuery plugin) for allowing multiple selection of instances for the view, that would be great too!
In my opinion, I would take advantage of the existing update method to add the relationship between Interest and Venue. I can do like this:
def update
#venue = Venue.find(params[:id])
#venue.update_attributes(params[:venue_params])
if params[:interest_ids].present?
#venue.interests = Interest.where(id: params[:interest_ids])
#venue.save
end
#more code to handle the rendering
end

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

in nested form- Can't mass-assign protected attributes:

I have read through several threads and nothing so far. I am trying to nest one form in another. I am getting the can't mass assign protected attributes error. \
app/controllers/projects_controller.rb:46:in new'
app/controllers/projects_controller.rb:46:increate'
Projects_controller.rb
def create
#project = Project.new(params[:project])
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render json: #project, status: :created, location: #project }
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
project.rb
WF::Application.routes.draw do
resources :line_items
resources :projects do
resources :line_items
end
devise_for :users
get 'about' => 'pages#about'
get 'Production' => 'projects#index'
root :to => 'pages#home'
end
here is the error...
ActiveModel::MassAssignmentSecurity::Error in ProjectsController#create
Can't mass-assign protected attributes: line_item
here is my project model
class Project < ActiveRecord::Base
attr_accessible :quantity
# may be unnessary
attr_accessible :line_items_attributes
belongs_to :user
has_many :line_items
accepts_nested_attributes_for :line_items, :allow_destroy => true
end
Assuming you're trying to create line items through your project model, you'll need to make sure you have the following lines in your Project model:
# project.rb
Class Project < ActiveRecord::Base
attr_accessible :line_items_attributes
accepts_nested_attributes_for :line_items
...
end
Rails is trying to protect you from accidentally assigning values you don't mean to.
You can tell Rails what values are ok to assign in this way:
attr_accessible :value1, :value2
If you add that line to the top of the Project model (replace :value1 and :value2 with the actual names of your columns), it should allow you to do what you're attempting.
For more info, here's the docs.

Resources