has_many through & Collection Select issues - ruby-on-rails

I'm stumped. I'm getting an error of unknown attribute 'products_part' for Part. I'm starting with trying to create a new part that is associated with many different products through the products_parts table. Relevant code:
# schema.rb
create_table "products_parts", force: :cascade do |t|
t.integer "product_id"
t.integer "part_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Just in case it's relevant, there is a product_id column existing on the parts table from my existing setup that only allowed one part per product. I don't think this would interfere though?
# part.rb
class Part < ApplicationRecord
has_many :products_parts
has_many :products, through: :products_parts
accepts_nested_attributes_for :products_parts, :allow_destroy => true
end
# products_part.rb
class ProductsPart < ApplicationRecord
belongs_to :product
belongs_to :part
end
# product.rb
class Product < ApplicationRecord
has_many :products_parts
has_many :parts, through: :products_parts
accepts_nested_attributes_for :parts, :allow_destroy => true
end
--
# parts_controller.html.erb
class PartsController < ApplicationController
before_action :set_part, only: [:show, :edit, :update, :destroy]
def new
#part = Part.new
#part.uploads.build
#products_parts = #part.products_parts.build
#product = Product.order(brand_name: :asc).order(manufacturer_model_number: :asc)
end
def create
#part = Part.new(part_params)
if #part.save
redirect_to part_path(#part), notice: '// Part was successfully created.'
else
render :new
end
end
private
def part_params
params.require(:part).permit!
end
end
Parameters being passed on submit:
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"f+ObKsfs2QNP6l1MEDGSj6EZERMpHT/7vVKjAumC1aQmeTKdlPJNeSv2IZwNgsVPnKt2Siqi9x5oMmD2Ti8kMQ==",
"part"=>
{"products_part"=>{"product_ids"=>["", "191", "7"]},
"manufacturer_model_number"=>"Screws-HB",
"notes"=>""},
"commit"=>"Create Part"}
-
# _form.html.erb
<%= bootstrap_form_for #part, url: parts_path, method: :post, :html => { :multipart => true } do |f| %>
<%= f.fields_for(#products_parts) do |ff| %>
<%= ff.collection_select(:product_ids, #product, :id, :product_select_with_model,
{:placeholder => "Select Product...", hide_label: true, :selected => #part.products.map(&:id)},
{:multiple => true, :class => 'newPartProductSearch', :style => "width:100%;"}) %>
<% end %>
<%= f.submit "Create Part", :style => "float:right;" %>
<% end %>
I am basing a lot of what I did here off of help from this post.
If anybody has any ideas on what direction I can go to start fixing this, it would be appreciated!

Replace the _form with the following code:
# _form.html.erb
<%= bootstrap_form_for #part, url: parts_path, method: :post, :html => { :multipart => true } do |f| %>
<%= f.collection_select(:product_ids, Product.all, :id, :name,
{include_blank: false, :include_hidden => false, :selected => #part.products.map(&:id)},
{:multiple => true}) %>
<%= f.submit "Create Part", :style => "float:right;" %>
<% end %>
It is not tested. But hope it'll work.

Related

ROR Active Record not save data correcty

Hi guys i have a problem and i dont' know how to solve it, i'm really new on the ROR's world.
preamble : each municiplaty has many itinerary, so :
1) i've created the itinerary table with this migration :
class CreateItineraries < ActiveRecord::Migration
def change
create_table :itineraries do |t|
t.string :title
t.string :json
t.integer :muncipality_id
t.text :description
t.boolean :published, :default => true, :null => false
t.timestamps null: false
end
end
end
2) i've added the municipality_id reference to the itineraries table, with this migration :
class AddMunicipalityIdToItineraries < ActiveRecord::Migration
def change
add_reference :itineraries, :municipality, index: true, foreign_key: true
end
end
3) i've created another table for the translations of itineraries :
class AddTranslationTablesForItineraries < ActiveRecord::Migration
def up
Itinerary.create_translation_table!({
:title => :string
}, {
:migrate_data => true
})
end
def down
add_column :itineraries, :title, :string
Itinerary.drop_translation_table! :migrate_data => true
end
end
now, the problem is when i try to save the data from the relative simple_form, it save the itinerary's title only in the translations table, why?!
here the code of the simple_form :
<%= simple_form_for [:admin, #municipality, #itinerary], url: #url, :html => {:class => ''} do |f| %>
<%= render 'application/translation_form_heading' %>
# ...
<%= f.input :title, required: true %>
<%= f.input :description, label: 'description', :as => :ckeditor, :input_html => {ckeditor: {toolbar: get_toolbar('default')},:rows => 15} %>
<%= f.input :json, required: true, label: 'GeoJSON', as: :text, :input_html => {:rows => 15} %>
# ...
<button type="submit" class="btn btn-primary pull-right">Save itinerary</button>
<% end %>
maybe it's a newbie question, but i don'r really know how to solve it, thank you!
edit : here the code of the itinerariesController :
class Admin::ItinerariesController < InheritedResources::Base
layout 'admin'
before_filter :authenticate_admin!
before_filter :set_page_title
load_and_authorize_resource
actions :all, :except => [:show]
belongs_to :municipality
def index
#itineraries = Itinerary.ordered
end
def new
#url = admin_municipality_itineraries_path(params[:municipality_id])
new!
end
def edit
#url = admin_municipality_itinerary_path(params[:municipality_id], params[:id])
edit!
end
def update
unless params[:translate_to].blank?
I18n.with_locale(params[:translate_to]) {
update!
}
else
update!
end
end
def set_page_title
#page_title = PointOfInterest.model_name.human(:count => 2).titleize
end
def create
create! {
admin_municipality_itineraries_path
}
end
private
def permitted_params
params.permit(:itinerary => [:id, :title, :json,:description, :municipality_id] )
end
end
Try to update this one in controller
private
def permitted_params
params.permit(:itinerary => [:id, :title, :description, :municipality_id, :json] )
end
You need to permit JSON value in params always at the end

Unpermitted parameter simple_form

I am trying to create a nested form with Simple_fields in ruby 4.
However, every time i try to enter data into the form I get a unpermitted parameter error in the server console after trying to submit.
I already tried the solutions found in the simple_form wiki and did some testing, but that doesn't seem to work.
The _form:
<%= simple_form_for(#enquiry) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<H1>Algemene informatie</H1>
<%= f.input :reference, placeholder: 'Referentie' %>
<br>
<%= f.label :Locatie %>
<%= f.select :location, [['Chemiepark', 'chemiepark'], ['Farmsum', 'farmsum'], ['Winschoten', 'winschoten']] %>
<br>
<%= f.input :description, placeholder: 'Omschrijving' %>
<br>
<%= f.input :date %>
<br>
<%= f.input :amount, placeholder: 'Aantal' %>
</div>
<hr>
<% if false %>
<div class="form-inputs">
<%= f.simple_fields_for :enquiry_measures do |e| %>
<H1>Maatregelen</H1>
<%= e.input :responsible, placeholder: 'Verantwoordelijke' %>
<br>
<%# e.input :needed, as: :check_boxes,
collection: ["ja", "nee"] %>
<% end %>
<br>
</div>
<% end %>
<div class="form-inputs">
<%= f.simple_fields_for :tools do |t| %>
<% #enquiry.tools.each do |tool| %>
<%= field_set_tag 'Tool' do %>
<%= f.simple_fields_for "tool_attributes[]", tool do |tf| %>
<h1>Gereedschappen</h1>
<br>
<%= tf.input :handtool, placeholder: 'Handgereedschap' %>
<% end %>
<% end %>
<% end %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
The strong attributes plus what i tested:
def enquiry_params
# was gegenereerd door de scaffold params.fetch(:enquiry, {})
params.require(:enquiry).permit(:reference, :location, :description, :date, :amount,
:enquiry_measures_attributes => [:done, :responsible, :needed], :tools_attributes => [:handtool] )
#:enquiry_measures_attributes => [:done, :responsible, :needed])
#enquiry_measure_attributes: [:done, :responsible, :needed] )
update
code from models
class Enquiry < ActiveRecord::Base
#ophalen van andere tabellen voor het formulier. Has_many is 1 op veel relatie
#accepts_nested_attributes Nested attributes allow you to save attributes on associated records through the paren
# de dere regel zorgt ervoor dat de maatregelen worden opgehaald via de tussentabel enquiry_measures.
has_many :enquiry_measures, :class_name => 'EnquiryMeasure' #, inverse_of: :Enquiry
accepts_nested_attributes_for :enquiry_measures, :allow_destroy => true
has_many :measures, -> { uniq }, :class_name => 'Measure', :through => :enquiry_measures, dependent: :destroy
accepts_nested_attributes_for :measures, :allow_destroy => false
has_many :controls, :class_name => 'Control' #, inverse_of: :Enquiry
has_many :applicants, :class_name => 'Applicant' #, inverse_of: :Enquiry
has_many :agrees, :class_name => 'Agree' #, inverse_of: :Enquiry
has_many :signatures, :class_name => 'Signature' #, inverse_of: :Enquiry
accepts_nested_attributes_for :signatures, :allow_destroy => false
has_many :tools, :class_name => 'Tool', :dependent => :destroy #, inverse_of: :Enquiry
accepts_nested_attributes_for :tools, :allow_destroy => true
#:dependent => :destroy zorgt ervoor dat de foreign record ook word verwijderd.
#de instances van andere tabellen:
e = Enquiry.new
e.enquiry_measures.build(:enquiry_id => :id)
e.measures.build
# 28-11 MG de pagina's die in het form worden gebruikt.
cattr_accessor :form_steps do
%w(basic when measurements tool)
end
attr_accessor :form_step
validates :reference, presence: true, if: -> { required_for_step?(:basic) }
validates :amount, :date, presence: true, if: -> { required_for_step?(:when) }
#validates :needed, presence: true, if: -> { required_for_step?(:measurements) }
def required_for_step?(step)
return true if form_step.nil?
return true if self.form_steps.index(step.to_s) <= self.form_steps.index(form_step)
end
#voor het mailen met behulp van de mailgem:
# Declare the e-mail headers. It accepts anything the mail method
# in ActionMailer accepts.
def headers
{
:subject => "My Contact Form",
:to => "marco.groenhof#jpbgroep.nl",
:from => %("#{name}" <#{email}>)
}
end
end
and 1 of the related models: in this case enquiry_measure
class EnquiryMeasure < ActiveRecord::Base
belongs_to :enquiry
validates_presence_of :enquiry
has_many :measure
#serialize zodat de data uit de collection select met multiple: true op kan worden geslagen.
serialize :measure
end
and tools:
class Tool < ActiveRecord::Base
belongs_to :enquiry, :class_name => 'Enquiry' #, inverse_of: :applicant
validates_presence_of :enquiry
end
I know class_name is not really needed anymore.
UPDATE
The logging:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"i3YukMoOaYEuUdxk6kmhoQ5q9uLQHHISW+NAU/L+kNjSwMZERmdIIVXZvJUh0vTnEPidaMvMEIlVT/aTlkTNPw==", "enquiry"=>{"reference"=>"Test", "location"=>"chemiepark", "description"=>"3ro0qjhrojeofj", "date(1i)"=>"2017", "date(2i)"=>"1", "date(3i)"=>"3", "amount"=>"2", "tools_attributes"=>{"0"=>{"handtool"=>"Hamer"}}}, "commit"=>"Create Enquiry"}
The only weird thing i see is the "tools_attributes"=>{"0"=>{"handtool"=>"Hamer"}}}
Why is that 0 there? Could it be the id, because that would make sense to why i can not save.
And just to make sure, this is the tool tabel and foreign key:
add_index "tools", ["enquiry_id"], name: "index_tools_on_enquiry_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "name", limit: 255
t.string "email", limit: 255
t.string "password_digest", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "tools", "enquiries"
UPDATE 4/01
Just installed rails panel to see what that would say, but i keep thinking the problem is within the parameters:
{"reference":"test","location":"chemiepark","description":"iwopjf","date(1i)":"2017","date(2i)":"1","date(3i)":"4","amount":"2","tools_attributes":{"0":{"handtool":"hamer"}}}
Why does it keep sending that 0? i suspect it to be the tool id, which would declare the not being able to save.
Try making you strong parameter as
params.require(:enquiry).permit(:reference, :location, :description, :date, :amount, enquiry_measures_attributes: [:id, :done, :responsible, :needed, :_destroy], tools_attributes: [:id, :handtool, :_destroy] )
And your model that is being nested should be something as below. Try doing this once.
class Tool < ActiveRecord::Base
# For a while let's not have any validation.
end
Hope this will work in your case as I fix it for my own.
I decided to updatew this question as i got the answer that helped me. It may not be the completely correct answer, but i managed to solve my issue by using the default form_for in uby on Rails. A bit more coding work, but it does work.

can't write unknown attribute `scrapbook_entry_id'

Attempting to add data to a join table of scrapbook_entries which has_one :scrapbook and has_one :recipe.
:recipe and :scrapbook already exist. I am trying to add them to link them with the scrapbook_entries table.
form_for adding to scrapbook_entries table:
<%= form_for(#scrapbook_entry, :url => scrapbook_entries_path(params[:id])) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%=f.select(:scrapbook_id, current_user.scrapbooks.collect {|p| [ p.name, p.id ] }, {prompt: 'Select Scrapbook...'})%>
<%= f.hidden_field :recipe_id, :value => #recipe.id %>
</div>
<%= f.submit "Save", class: "btn btn-large btn-primary" %>
<% end %>
scrapbook_entries_controller:
def create
#recipe = Recipe.find(params[:scrapbook_entry][:recipe_id])
#scrapbook = current_user.scrapbooks.find(params[:scrapbook_entry][:scrapbook_id])
#entry = #scrapbook.scrapbook_entries.build(scrapbook: #scrapbook)
if #entry.save
flash[:success] = "Added '#{#recipe.name}' to scrapbook '#{#scrapbook.name}'"
else
flash[:error] = "Could not add to scrapbook"
end
redirect_to #recipe
end
scrapbook.rb
has_many :recipes, through: :scrapbook_entries
has_many :scrapbook_entries
recipe.rb
has_many :scrapbooks, through: :scrapbook_entries
scrapbook_entry.rb
has_one :recipe
has_one :scrapbook
On submitting the form to the controller I am getting a error:
can't write unknown attribute `scrapbook_entry_id'
Can anyone tell me what I am doing wrong?
Update:
schema.rb
create_table "scrapbook_entries", force: true do |t|
t.integer "scrapbook_id"
t.integer "recipe_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
Your scrapbook_entr.rb should contain
belongs_to :recipe
belongs_to :scrapbook
and not has_one!
You always use belongs_to when your table contains a foreign key to another table, which in this case definitely is the case!

Why doesn't my user follow/unfollow button work?

I am working on building an application (following Michael Hartl's chapter 11) where users can follow projects that are created by other users.
I created a ProjectRelationship model to hold two components: follower_id for the users and projectuser_id for the projects. The foreign keys have been set up as such.
Right now, my _follow_form.html.erb page renders "follow" or "unfollow" depending on whether the current_user is following the project. Please see my code below and see what I am missing.
Right now, the follow button is generated on each project show page. But when I click the button follow button that is generated by _follow.html.erb, it does not seem to follow the project or update the count when I call #project.followers.count as the POST is not happening.
And thus, when I click follow button, the URL becomes all jumbled. See example:
#Goes from
domain.com/projects/21
#to
domain.com/projects/21?utf8=%E2%9C%93&authenticity_token=5EQmU0EkHB5yKDYakqL78piMWzZl0CfdpHFEqBeQiN4%3D&project_relationship%5Bprojectuser_id%5D=21&commit=Follow%22
**Update:
It seems to work now, but I'm not sure if I really changed anything but got rid of the follower_id index :unique => true through a migration change.
schema.rb
create_table "project_relationships", :force => true do |t|
t.integer "follower_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "projectuser_id"
end
add_index "project_relationships", ["follower_id"], :name => "index_project_relationships_on_follower_id", :unique => true
add_index "project_relationships", ["projectuser_id"], :name => "index_project_relationships_on_projectuser_id"
routes.rb
resources :projects do
resources :comments
member do
get :following
end
end
resources :project_relationships, only: [:create, :destroy]
project_relationship.rb
class ProjectRelationship < ActiveRecord::Base
attr_accessible :projectuser_id
belongs_to :user, foreign_key: "follower_id"
belongs_to :project, foreign_key: "projectuser_id"
end
project.rb
has_many :project_relationships, foreign_key: "projectuser_id"
has_many :favorited_by, through: :project_relationships, source: :user
user.rb
has_many :project_relationships, foreign_key: "follower_id"
has_many :followed_projects, through: :project_relationships, source: :project
def following_project?(project)
project_relationships.find_by_follower_id(project.id)
end
def follow_project!(project)
project_relationships.create!(projectuser_id: project.id)
end
def project_unfollow!(project)
project_relationships.find_by_projectuser_id(project.id).destroy
end
project_relationships_controller.rb
class ProjectRelationshipsController < ApplicationController
def create
#project = Project.find(params[:project_relationship][:projectuser_id])
current_user.follow_project!(#project)
redirect_to #project
end
def destroy
#project = ProjectRelationship.find(params[:id]).followed_project
current_user.project_unfollow!(#project)
redirect_to #project
end
end
projects/show.html.erb
<%= render 'follow_form' if signed_in? %>
projects/_follow_form.html.erb
<% if current_user.following_project?(#project) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
projects/_follow.html.erb
<%= form_for(current_user.project_relationships.build(projectuser_id: #project.id)) do |f| %>
<div><%= f.hidden_field :projectuser_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
projects/_unfollow.html.erb
<%= form_for(current_user.project_relationships.find_by_projectuser_id(#project),
html: { method: :delete }) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
First of all - if you run projectfollow!(project) and projectunfollow!(project) in your console (with a user, project etc) do they work properly?
For your forms try the following instead and see if it works:
<%= form_for(current_user.project_relationships.build, url: project_relationships_path(project_id: #project.id)) do |f| %>
Then in your project relationships controller:
class ProjectRelationshipsController < ApplicationController
def create
#project = Project.find(params[:project_id])
current_user.projectfollow!(#project)
redirect_to #project
end
end
So if your create URL is /project_relationships (via POST), the above should post to /project_relationships?project_id=5 and then the controller can find that project.
Also, try to rename your methods so they make sense:
def following_project?(project)
end
def follow_project!(project)
end
def unfollow_project!(project)
end
Now current_user.following_project?(project) makes a lot of sense!
Update
Ok, I think the following is the problem, in your create action you're getting the id from the params:
#project = Project.find(params[:project_relationship][:projectuser_id])
However in your form you're not setting the value of the hidden field:
<%= f.hidden_field :projectuser_id %>
Change it to the following and see if it works:
<%= f.hidden_field :projectuser_id, value: #project.id %> # or wherever the id is from
The problem was that my follow/unfollow form was embedded in another form which caused the error. Once taken out, worked!

I am getting the error NoMethodError in CarController#add

NoMethodError in CarController#add
undefined method `user_id=' for #<Car:0x7160c70>
RAILS_ROOT: C:/Users/Jatinder/BitNami RubyStack projects/mercedes_mod 2
add.html (for adding car)
<h1>Ask a Question or Discuss Your Car</h1>
<%= error_messages_for :car %>
<br>
<p>You can ask anything related to cars even if its not a Mercedes!</p>
<% form_for :car do |f| %>
<p>
<%= f.label :name, "Title of Question" %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :description, "Describe Your Question" %>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit "Add" %>
</p>
<% end %>
def add in car_controller.rb:
def add
#title = "Ask a New Question"
if request.post?
#car = Car.new(params[:car])
#car.user_id = User.logged_in(session).id
if #car.save
flash[:notice] = "Car #{#car.name} added!"
redirect_to :controller => :car, :action => :index
end
end
end
car.rb model:
class Car < ActiveRecord::Base
belongs_to :user
belongs_to :subject
validates_presence_of :name, :description
end
routes.rb
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
map.resources :car, :users => { :delete => :get }
map.root :controller => "main"
map.root :controller => "car", :action => "destroy"
end
create_cars migration:
class CreateCars < ActiveRecord::Migration
def self.up
create_table :cars do |t|
t.interger :user_id
t.string :name
t.string :description
t.timestamps
end
end
def self.down
drop_table :cars
end
end
Two errors:
user_id is declared as an "inte r ger"
I think you meant to write user = rather than user_id =
Chuck is correct. Your user_id is declared as an "interger". Consider using
t.references :user
instead of t.integer :user_id.
Also verify that your user model declares it's connection to the car model using has_one or has_many.
If User.logged_in(session) returns a User model object, you can do #car.user = User.logged_in(session) If not your code should work fine.
I want to know how is relation defined in your User model, might be you not defined the relation in User model due which its not able to find the user_id

Resources