passing an id from one controller to another - RAILS 5 - ruby-on-rails

How can I automatically place/pass the product_id in the input field?
i have 2 tables products & capturepages in my
schema
products
t.string "name"
t.string "description"
capturepages
t.string "name"
t.string "email"
t.integer "product_id"
models
product.rb
has_many :capturepages
capturepage.rb
belongs_to :product
capturepages controller
class CapturepagesController < ApplicationController
before_action :set_capturepage, only: [:show, :edit, :update, :destroy]
def new
#capturepage = Capturepage.new
#product_id = params[:product_id]
#product = Product.find(params[:product_id])
end
def create
#capturepage = Capturepage.new(capturepage_params)
#product = #capturepage.product
respond_to do |format|
if #capturepage.save
format.html { redirect_to #product.affiliatecompanylink, notice: 'Capturepage was successfully created.' }
format.json { render :show, status: :created, location: #capturepage }
else
format.html { render :new }
format.json { render json: #capturepage.errors, status: :unprocessable_entity }
end
end
end
private
def set_capturepage
#capturepage = Capturepage.find(params[:id])
end
def capturepage_params
params.require(:capturepage).permit(:name, :email, :product_id)
end
end
views/products.show.html.erb
when the user clicks on the below link:
<%= link_to "buy now", new_capturepage_path(product_id: #product.id), target:"_blank" %>
they are directed to the capturepage form page
views/capturepages/_form.html.erb
<%= simple_form_for(#capturepage) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :product_id, value: #product_id %>
<%= f.input :name, placeholder: "Your Name", label: false %>
<%= f.input :email, placeholder: "Your Email", label: false %>
</div>
<div class="form-actions">
<%= f.button :submit, "get product" %>
</div>
<% end %>
the url states: http://localhost:3000/capturepages/new?product_id=1
capturing the product_id but the product_id input is empty:

As you are using simple_form, you should place value inside input_html. Below code should fix your problem
<%= f.input :product_id, input_html: { value: #product_id } %>

Related

Rails - Nest Attributes Issues

I am having issues understanding this.
What am I trying to accomplish?
Selected items in dropdown submitted to inventory.
Change the status of each item in a form in its own model.
Problem
I submit a form and the status of each item in the dropdown doesn't get submitted.
Any help would be appreciated.
Thanks in advance!
Form Code
<%= form_for(#inventory, html: {class: "form-horizontal"}) do |f| %>
<% if #inventory.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#inventory.errors.count, "error") %> prohibited this inventory from being saved:</h2>
<ul>
<% #inventory.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :tablet_id, "Tablet #", class: "col-md-2 control-label" %>
<div class="col-md-4">
<%= select("inventory", "tablet_id", Tablet.where("status = '1'").all.collect{ |t| [t.alias, t.id] }, {}, { class: "form-control"} ) %>
</div>
</div>
<%= f.fields_for :tablet do |t| %>
<%= t.hidden_field :status, value: 2 %>
<% end %>
<div class="form-group">
<%= f.label :chauffeur_id, "Chauffeur #", class: "col-md-2 control-label" %>
<div class="col-md-4">
<%= select("inventory", "chauffeur_id", Chauffeur.where("status = '1'").all.collect{ |t| [t.chaufNum, t.id] }, {}, { class: "form-control"} ) %>
</div>
</div>
<%= f.fields_for :chauffeur do |t| %>
<%= t.hidden_field :status, value: 2 %>
<% end %>
<div class="form-group">
<%= f.label :vehicle_id, "Vehicle #", class: "col-md-2 control-label" %>
<div class="col-md-4">
<%= select("inventory", "vehicle_id", Vehicle.where("status = '1'").all.collect{ |t| [t.vehNum, t.id] }, {}, { class: "form-control"} ) %>
</div>
</div>
<%= f.fields_for :vehicle do |t| %>
<%= t.hidden_field :status, value: 2 %>
<% end %>
<div class="form-group">
<div class="col-md-2 col-md-offset-2">
<%= f.submit class: "btn btn-sm btn-success" %>
</div>
</div>
<% end %>
Model (Inventory)
class Inventory < ActiveRecord::Base
belongs_to :tablet
belongs_to :chauffeur
belongs_to :vehicle
accepts_nested_attributes_for :tablet
accepts_nested_attributes_for :chauffeur
accepts_nested_attributes_for :vehicle
has_paper_trail
validates :tablet_id, :chauffeur_id, :vehicle_id, presence: true
validates :tablet_id, :chauffeur_id, :vehicle_id, uniqueness: { message: " is already checked out." }
end
Inventory Controller
class InventoriesController < ApplicationController
before_action :authenticate_user!
before_filter :set_paper_trail_whodunnit
before_action :set_inventory, only: [:show, :edit, :update, :destroy]
# GET /inventories
# GET /inventories.json
def index
#inventories = Inventory.all.paginate(:page => params[:page], :per_page => 15)
end
# GET /inventories/1
# GET /inventories/1.json
def show
#versions = PaperTrail::Version.order('created_at DESC')
end
# GET /inventories/new
def new
#inventory = Inventory.new
end
# GET /inventories/1/edit
def edit
end
def history
#versions = PaperTrail::Version.order('created_at DESC')
end
# POST /inventories
# POST /inventories.json
def create
# #inventory = Inventory.new(inventory_params)
render plain: params[:inventory].inspect
# respond_to do |format|
# if #inventory.save
# format.html { redirect_to #inventory, notice: 'Inventory was successfully created.' }
# format.json { render :show, status: :created, location: #inventory }
# else
# format.html { render :new }
# format.json { render json: #inventory.errors, status: :unprocessable_entity }
# end
# end
end
# PATCH/PUT /inventories/1
# PATCH/PUT /inventories/1.json
def update
respond_to do |format|
if #inventory.update(inventory_params)
format.html { redirect_to #inventory, notice: 'Inventory was successfully updated.' }
format.json { render :show, status: :ok, location: #inventory }
else
format.html { render :edit }
format.json { render json: #inventory.errors, status: :unprocessable_entity }
end
end
end
# DELETE /inventories/1
# DELETE /inventories/1.json
def destroy
#inventory.destroy
respond_to do |format|
format.html { redirect_to inventories_url, notice: 'Inventory was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_inventory
#inventory = Inventory.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def inventory_params
params.require(:inventory).permit(:tablet_id, :chauffeur_id, :vehicle_id, tablet_attributes: [:status => '2'], chauffeur_attributes: [:status => '2'], vehicle_attributes: [:status => '2'])
end
end
Clean all your nested attribute code. This is not what you want. So model like this:
class Inventory < ActiveRecord::Base
belongs_to :tablet
belongs_to :chauffeur
belongs_to :vehicle
has_paper_trail
validates :tablet_id, :chauffeur_id, :vehicle_id, presence: true
validates :tablet_id, :chauffeur_id, :vehicle_id, uniqueness: { message: " is already checked out." }
end
Now, what you want to use a rails callback so that when you create an inventory then you update the status of other things. This goes on your model too:
class Inventory < ActiveRecord::Base
...
after_create :update_status
protected
def update_status
self.tablet.update_attribute(:status, 2)
self.chauffeur.update_attribute(:status, 2)
self.vehicle.update_attribute(:status, 2)
end
end
Also remember to clean all your fields_for code and your strong parameters on your controller...you don't need the nested ones anymore.

f.collection_select with name

I hope someone can help me.
I have a table with the name "location_location_relationships". If you create a new entry you can select two locations (predecessor and successor) which are from a "locaions" table. In addition you can select a tour. These are coming from table "tours". The locations selection is working. But the tours makes some problems. First I had nothing in the models everything worked but the selection wrote not the names but the ids in the "location_location_relationships" table. But I want the names in there. So I completed the models of "tours" and "location_location_relationships". In the selection there are the names of the tours now but if I press the Button "create" I get an error massage:
Tour(#96769428) expected, got String(#1848192)
and it shows me the error in the location_location_relationship_controller.rb in:
'def create
#location_location_relationship = LocationLocationRelationship.new(location_location_relationship_params)'
Has anyone an idea what I did wrong?
Thank you very much for your help in advance!
This is my location_location_relationships_form.html.erb where the collection_select is in:
<%= form_for(#location_location_relationship) do |f| %>
<% if #location_location_relationship.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#location_location_relationship.errors.count, "error") %> prohibited this location_location_relationship from being saved:</h2>
<ul>
<% #location_location_relationship.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label 'Von Ort' %><br />
<%= f.collection_select :predecessor_id, Location.all, :id, :name %>
</div>
<div class="field">
<%= f.label 'Zu Ort' %><br />
<%= f.collection_select :successor_id, Location.all, :id, :name %>
</div>
<div class="field">
<%= f.label 'Tour' %><br>
<%= f.collection_select :tour, Tour.all, :id, :name_of_tour, prompt: true %>
</div>
<div class="field">
<%= f.label 'Distanz' %><br>
<%= f.text_field :distance, type: "number", min:0 %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My model of the location_location_relationships:
class LocationLocationRelationship < ActiveRecord::Base
belongs_to :successor, class_name: "Location"
belongs_to :predecessor, class_name: "Location"
validates :successor_id, presence: true
validates :predecessor_id, presence: true
belongs_to :tour
validates :tour, presence: true
validates :distance, :numericality => true
# validates :sequence, :numericality => {:only_integer => true}
# validates :binary_variable, :numericality => {:only_integer => true}
end
And my tours model:
class Tour < ActiveRecord::Base
#validates :tour, presence: true
has_many :location_location_relationships
def name_of_tour
name
end
end
And the location_location_relationships controller:
class LocationLocationRelationshipsController < ApplicationController
before_action :set_location_location_relationship, only: [:show, :edit, :update, :destroy]
# GET /location_location_relationships
# GET /location_location_relationships.json
def index
#location_location_relationships = LocationLocationRelationship.all
end
# GET /location_location_relationships/1
# GET /location_location_relationships/1.json
def show
end
# GET /location_location_relationships/new
def new
#location_location_relationship = LocationLocationRelationship.new
end
# GET /location_location_relationships/1/edit
def edit
end
# POST /location_location_relationships
# POST /location_location_relationships.json
def create
#location_location_relationship = LocationLocationRelationship.new(location_location_relationship_params)
respond_to do |format|
if #location_location_relationship.save
format.html { redirect_to #location_location_relationship, notice: 'Die Distanz wurde angelegt.' }
format.json { render :show, status: :created, location: #location_location_relationship }
else
format.html { render :new }
format.json { render json: #location_location_relationship.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /location_location_relationships/1
# PATCH/PUT /location_location_relationships/1.json
def update
respond_to do |format|
if #location_location_relationship.update(location_location_relationship_params)
format.html { redirect_to #location_location_relationship, notice: 'Die Distanz wurde aktualisiert.' }
format.json { render :show, status: :ok, location: #location_location_relationship }
else
format.html { render :edit }
format.json { render json: #location_location_relationship.errors, status: :unprocessable_entity }
end
end
end
# DELETE /location_location_relationships/1
# DELETE /location_location_relationships/1.json
def destroy
#location_location_relationship.destroy
respond_to do |format|
format.html { redirect_to location_location_relationships_url, notice: 'Die Distanz wurde gelöscht.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_location_location_relationship
#location_location_relationship = LocationLocationRelationship.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def location_location_relationship_params
params.require(:location_location_relationship).permit(:predecessor_id, :successor_id, :tour, :distance, :sequence, :binary_variable)
end
end
Tour(#96769428) expected, got String(#1848192)
You should change tour to tour_id
<div class="field">
<%= f.label 'Tour' %><br>
<%= f.collection_select :tour_id, Tour.all, :id, :name_of_tour, prompt: true %>
</div>
And also in location_location_relationship_params
def location_location_relationship_params
params.require(:location_location_relationship).permit(:predecessor_id, :successor_id, :tour_id, :distance, :sequence, :binary_variable)
end

Turn A String Of Clothes Sizes "xs,s,m,l,xl" into some you can select

Hello I have an Items Model and a Categories Model. When creating a Shirt category you can create all the sizes you expect a Shirt category to have.
At the moment the sizes are a string "XS, S, M, L, XL, XLL"
How do i make it so its something you can select?
For instance when you create an Yellow Shirt item you might only have XS and L available.
See below
2.2.1 :002 > c = Category.last
Category Load (0.3ms) SELECT "categories".* FROM "categories" ORDER BY "categories"."id" DESC LIMIT 1
=> #<Category id: 14, name: "Shirt", ancestry: nil, created_at: "2015-09-01 10:09:32", updated_at: "2015-09-01 10:09:32", sizes: "XS, S, M, L, XL, XLL">
2.2.1 :003 > c
=> #<Category id: 14, name: "Shirt", ancestry: nil, created_at: "2015-09-01 10:09:32", updated_at: "2015-09-01 10:09:32", sizes: "XS, S, M, L, XL, XLL">
2.2.1 :004 > c.sizes
=> "XS, S, M, L, XL, XLL"
Categories Controller
class CategoriesController < ApplicationController
before_action :set_category, only: [:show]
before_action :admin_user, only: [:destroy, :index, :edit]
def index
#categories = Category.all
end
def show
#tags = Item.where(category_id: #category.id).tag_counts_on(:tags)
if params[:tag]
#items = Item.tagged_with(params[:tag])
else
#items = Item.where(category_id: #category.id).order("created_at DESC")
end
end
def new
#category = Category.new
end
def edit
end
def create
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.html { redirect_to #category, notice: 'Category was successfully created.' }
format.json { render :show, status: :created, location: #category }
else
format.html { render :new }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #category.update(category_params)
format.html { redirect_to #category, notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: #category }
else
format.html { render :edit }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
def destroy
#category.destroy
respond_to do |format|
format.html { redirect_to categories_url, notice: 'Category was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_category
#category = Category.find(params[:id])
end
def category_params
params.require(:category).permit(:name, :sizes, :parent_id)
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.try(:admin?)
end
end
Categories Form
<div class="container">
<div class=“row”>
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-primary">
<div class="panel-body">
<%= simple_form_for(#category) do |f| %>
<div class="form-inputs">
<%= f.input :name %>
<%= f.input :sizes %>
<%= f.collection_select :parent_id, Category.order(:name), :id, :name, include_blank: true %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
Incase you need the Items view
<h1>Create New item</h1>
<div class="container">
<div class=“row”>
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-primary">
<div class="panel-body">
<%= simple_form_for #item, html: { multipart: true } do |f| %>
<%= f.input :image%>
<%= f.collection_select :category_id, Category.order(:name), :id, :name, include_blank: true, :prompt => "Select One Category" %>
<%= f.input :tag_list %>
<%= f.input :title%>
<%= f.input :price %>
<%= f.input :description %>
<%= f.button :submit, "Create new item", class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
</div>
</div>
Migration for turning sizes into an array.
class AddSizesToCategories < ActiveRecord::Migration
def change
add_column :categories, :sizes, :string, array: true, default: []
end
end
You could use the enum type for this. In your Category model you could define all possible values:
enum sizes: [:xs, :s, :m, :l, :xl, :xll]
In the database enum types are stored as integers, so you could then use an array of integers, so basically in your migration you would only have to change it to:
add_column :categories, :sizes, :integer, array: true, default: []
In your form you can then get the values from this enum type like this:
<%= f.input :sizes, collection: Category.sizes.keys, as: :check_boxes, input_html: { multiple: true } %>
In your categories_controller you also need to allow the array for the sizes parameter like this:
def category_params
params.require(:category).permit(:name, :parent_id, sizes: [])
end
You should create a array/enumrator for this and this can be accessible anywhere in app. So create a initialize.rb file under config/initializers.
## config/initializers/initialize.rb
CATEGORIES = [["XS","XS"],["S","S"],["M","M"],["L","L"],["XL","XL"],["XLL","XLL"]]
In your categories form change:
<%= f.input :sizes %>
to
<%= f.collection_check_boxes :sizes, CATEGORIES%>
When tou submit form and selected XS, L, XLL, You will get params params[:category][:sizes] like ["XS", "L", "XLL"]
Change that in string format and save to db. You are done

How to pre-populate collection_check_boxes in an edit form?

GitHub repo: https://github.com/Yorkshireman/mywordlist
I've googled the hell out of this one. I'm sure there's a way, possibly requiring some code inside a html options hash, but I can't work it out. Any ideas?
When visiting the _edit_word_form.html.erb partial for a Word that DOES have one or more categories, the Categories checkboxes are all unchecked, requiring the user to select them again, even if they don't want to change the Categories.
The text fields for the :title and :description ARE pre-populated (thankfully).
_edit_word_form.html.erb:
<%= form_for(#word) do %>
<%= fields_for :word, #word do |word_form| %>
<div class="field form-group">
<%= word_form.label(:title, "Word:") %><br>
<%= word_form.text_field(:title, id: "new_word", required: true, autofocus: true, class: "form-control") %>
</div>
<div class="field form-group">
<%= word_form.label(:description, "Definition:") %><br>
<%= word_form.text_area(:description, class: "form-control") %>
</div>
<% end %>
<%= fields_for :category, #category do |category_form| %>
<% if current_user.word_list.categories.count > 0 %>
<div class="field form-group">
<%= category_form.label(:title, "Choose from existing Categories:") %><br>
<%= category_form.collection_check_boxes(:category_ids, current_user.word_list.categories.all, :id, :title) do |b| %>
<%= b.label(class: "checkbox-inline") { b.check_box + b.text } %>
<% end %>
</div>
<% end %>
<h4>AND/OR...</h4>
<div class="field form-group">
<%= category_form.label(:title, "Create and Use a New Category:") %><br>
<%= category_form.text_field(:title, class: "form-control") %>
</div>
<% end %>
<div class="actions">
<%= submit_tag("Update!", class: "btn btn-block btn-primary btn-lg") %>
</div>
<% end %>
Relevant part of the words/index.html.erb:
<% current_user.word_list.words.alphabetical_order_asc.each do |word| %>
<tr>
<td>
<%= link_to edit_word_path(word) do %>
<%= word.title %>
<span class="glyphicon glyphicon-pencil"></span>
<% end %>
</td>
<td><%= word.description %></td>
<td>
<% word.categories.alphabetical_order_asc.each do |category| %>
<a class="btn btn-info btn-sm", role="button">
<%= category.title %>
</a>
<% end %>
</td>
<td>
<%= link_to word, method: :delete, data: { confirm: 'Are you sure?' } do %>
<span class="glyphicon glyphicon-remove"></span>
<% end %>
</td>
</tr>
<% end %>
words_controller.rb:
class WordsController < ApplicationController
before_action :set_word, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /words
# GET /words.json
def index
#words = Word.all
#quotes = Quote.all
end
# GET /words/1
# GET /words/1.json
def show
end
# GET /words/new
def new
#word = current_user.word_list.words.build
end
# GET /words/1/edit
def edit
end
# POST /words
# POST /words.json
def create
#word = Word.new(word_params)
respond_to do |format|
if #word.save
format.html { redirect_to #word, notice: 'Word was successfully created.' }
format.json { render :show, status: :created, location: #word }
else
format.html { render :new }
format.json { render json: #word.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /words/1
# PATCH/PUT /words/1.json
def update
#need to first remove categories from the word
#word.categories.each do |category|
#word.categories.delete category
end
#then push categories in from the category_params
if params["category"].include?(:category_ids)
(params["category"])["category_ids"].each do |i|
next if i.to_i == 0
#word.categories << Category.find(i.to_i) unless #word.categories.include?(Category.find(i.to_i))
end
end
if category_params.include?(:title) && ((params["category"])["title"]) != ""
#word.categories << current_user.word_list.categories.build(title: (params["category"])["title"])
end
respond_to do |format|
if #word.update(word_params)
format.html { redirect_to words_path, notice: 'Word was successfully updated.' }
format.json { render :show, status: :ok, location: #word }
else
format.html { render :edit }
format.json { render json: #word.errors, status: :unprocessable_entity }
end
end
end
# DELETE /words/1
# DELETE /words/1.json
def destroy
#word.destroy
respond_to do |format|
format.html { redirect_to words_url, notice: 'Word was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_word
#word = Word.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def word_params
params.require(:word).permit(:title, :description, :category_ids)
end
def category_params
params.require(:category).permit(:title, :category_ids, :category_id)
end
end
categories_controller.rb:
class CategoriesController < ApplicationController
before_action :set_category, only: [:show, :edit, :update, :destroy]
# GET /categories
# GET /categories.json
def index
#categories = Category.all
end
# GET /categories/1
# GET /categories/1.json
def show
end
# GET /categories/new
def new
#category = current_user.word_list.categories.build
end
# GET /categories/1/edit
def edit
end
# POST /categories
# POST /categories.json
def create
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.html { redirect_to #category, notice: 'Category was successfully created.' }
format.json { render :show, status: :created, location: #category }
else
format.html { render :new }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /categories/1
# PATCH/PUT /categories/1.json
def update
respond_to do |format|
if #category.update(category_params)
format.html { redirect_to #category, notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: #category }
else
format.html { render :edit }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# DELETE /categories/1
# DELETE /categories/1.json
def destroy
#category.destroy
respond_to do |format|
format.html { redirect_to categories_url, notice: 'Category was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_category
#category = Category.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def category_params
params.require(:category).permit(:title, :word_list_id, :category_ids)
end
end
word_lists_controller.rb:
class WordListsController < ApplicationController
before_action :set_word_list, only: [:show, :edit, :update, :destroy]
def from_category
#selected = current_user.word_list.words.joins(:categories).where( categories: {id: (params[:category_id])} )
respond_to do |format|
format.js
end
end
def all_words
respond_to do |format|
format.js
end
end
# GET /word_lists
# GET /word_lists.json
def index
#word_lists = WordList.all
end
# GET /word_lists/1
# GET /word_lists/1.json
def show
#words = Word.all
#word_list = WordList.find(params[:id])
end
# GET /word_lists/new
def new
#word_list = WordList.new
end
# GET /word_lists/1/edit
def edit
end
# POST /word_lists
# POST /word_lists.json
def create
#word_list = WordList.new(word_list_params)
respond_to do |format|
if #word_list.save
format.html { redirect_to #word_list, notice: 'Word list was successfully created.' }
format.json { render :show, status: :created, location: #word_list }
else
format.html { render :new }
format.json { render json: #word_list.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /word_lists/1
# PATCH/PUT /word_lists/1.json
def update
respond_to do |format|
if #word_list.update(word_list_params)
format.html { redirect_to #word_list, notice: 'Word list was successfully updated.' }
format.json { render :show, status: :ok, location: #word_list }
else
format.html { render :edit }
format.json { render json: #word_list.errors, status: :unprocessable_entity }
end
end
end
# DELETE /word_lists/1
# DELETE /word_lists/1.json
def destroy
#word_list.destroy
respond_to do |format|
format.html { redirect_to word_lists_url, notice: 'Word list was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_word_list
#word_list = WordList.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def word_list_params
params[:word_list]
end
end
word_list.rb:
class WordList < ActiveRecord::Base
belongs_to :user
has_many :words
has_many :categories
end
word.rb:
class Word < ActiveRecord::Base
belongs_to :word_list
has_and_belongs_to_many :categories
validates :title, presence: true
scope :alphabetical_order_asc, -> { order("title ASC") }
end
category.rb:
class Category < ActiveRecord::Base
has_and_belongs_to_many :words
belongs_to :word_list
validates :title, presence: true
scope :alphabetical_order_asc, -> { order("title ASC") }
end
schema.rb:
ActiveRecord::Schema.define(version: 20150609234013) do
create_table "categories", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "word_list_id"
end
add_index "categories", ["word_list_id"], name: "index_categories_on_word_list_id"
create_table "categories_words", id: false, force: :cascade do |t|
t.integer "category_id"
t.integer "word_id"
end
add_index "categories_words", ["category_id"], name: "index_categories_words_on_category_id"
add_index "categories_words", ["word_id"], name: "index_categories_words_on_word_id"
create_table "quotes", force: :cascade do |t|
t.text "content"
t.string "author"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
create_table "word_lists", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "words", force: :cascade do |t|
t.string "title"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "word_list_id"
end
add_index "words", ["word_list_id"], name: "index_words_on_word_list_id"
end
routes.rb:
Rails.application.routes.draw do
resources :quotes
resources :categories
resources :words
devise_for :users, controllers: { registrations: "users/registrations" }
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
root 'pages#home'
post 'create_word_and_category' => 'new_word#create_word_and_category'
end
The discussion might not be active anymore but I'll share my answer for the future visitors.
Adding "{ checked: #array.map(&:to_param) }" option as the last argument of collection_check_boxes may resolve your problem. Refer this link.
Example:
Suppose you have Software model and Platform(OS) model and want to choose one or more OS that support your software.
#views/softwares/edit.html.erb
<%= form_for #software do |f| %>
...
<%= f.label :supported_platform %>
<%= f.collection_check_boxes(:platform_ids, #platforms, :id, :platform_name, { checked: #software.platform_ids.map(&:to_param) }) %>
...
<%= f.submit "Save", class: 'btn btn-success' %>
<% end %>
note:
#software.platform_ids should be an array. If you are using SQLite, you have to convert string into array when you pull the data out. I tested it with SQLite and confirmed working as well. See my post for more detail.
This should be closer to what you were looking for:
<%= b.label(class: "checkbox-inline", :"data-value" => b.value) { b.check_box + b.text } %>
Try changing your _edit_word_form.html.erb like this
<%= form_for(#word) do |f| %>
<div class="field form-group">
<%= f.label(:title, "Word:") %><br>
<%= f.text_field(:title, id: "new_word", required: true, autofocus: true, class: "form-control") %>
</div>
<div class="field form-group">
<%= f.label(:description, "Definition:") %><br>
<%= f.text_area(:description, class: "form-control") %>
</div>
<%= f.fields_for :category do |category_form| %>
<% if current_user.word_list.categories.count > 0 %>
<div class="field form-group">
<%= category_form.label(:title, "Choose from existing Categories:") %><br>
<%= category_form.collection_check_boxes(:category_ids, current_user.word_list.categories.all, :id, :title) do |b| %>
<%= b.label(class: "checkbox-inline") { b.check_box + b.text } %>
<% end %>
</div>
<% end %>
<h4>AND/OR...</h4>
<div class="field form-group">
<%= category_form.label(:title, "Create and Use a New Category:") %><br>
<%= category_form.text_field(:title, class: "form-control") %>
</div>
<% end %>
<div class="actions">
<%= f.submit("Update!", class: "btn btn-block btn-primary btn-lg") %>
</div>
<% end %>
So user is editing a word from their word list, but you want to show checkboxes for all categories for all the words in their word list, checking those categories attached to the word being editing. Is that correct?
It looks like you're missing out the first parameter in #collection_check_boxes, which should be the object you call :category_ids on.
If the object is the user's word_list, then something like:
<%= category_form.collection_check_boxes(current_user.word_list, :category_ids, current_user.word_list.categories.all, :id, :title) do |b| %>
May not be the exact answer--I can't test it--but hope it gives you something to go on.
What's wrong
When you are calling category_form.collection_check_boxes(:category_ids, current_user.word_list.categories.all, :id, :title) within the fields_for :category, you are saying there is a method on #word.category called category_ids which will return the ids of the categories related to #word.category. The checkbox will be checked if there is a matching id both in category_ids results and in current_user.word_list.categories.all.
I don't think there is a #word.category or a #word.category.category_ids. I think there's #word.categories though.
How to fix it
That being said, my instinct tells me that you need to use something like:
<%= form_for(#word) do |f| %>
<div class="field form-group">
<%= f.label(:title, "Word:") %><br>
<%= f.text_field(:title, id: "new_word", required: true, autofocus: true, class: "form-control") %>
</div>
<div class="field form-group">
<%= f.label(:description, "Definition:") %><br>
<%= f.text_area(:description, class: "form-control") %>
</div>
<% if current_user.word_list.categories.count > 0 %>
<div class="field form-group">
<%= f.label(:categories, "Choose from existing Categories:") %><br>
<%= f.collection_check_boxes(:category_ids, current_user.word_list.categories.all, :id, :title) %>
</div>
<% end %>
<div class="actions">
<%= f.submit("Update!", class: "btn btn-block btn-primary btn-lg") %>
</div>
<% end %>
Note that I've moved the collection_check_boxes to the #word's form builder, as you are hoping to build the "categories" value for the current #word. I think this should be a step in the right direction anyway.

Rails 4 - Nested Routes and Form Parameters

When I'm trying to create a new "participation" in my Rails4 application and it seems like there is something wrong with my parameters. Actually this is not causing any problems in application (or I didn't notice it) but still I would like to fix it. You can see 2 "examination_id" parameters one of them is null and the other one is equal to 1.
REQUEST PARAMETERS:
{"utf8"=>"✓",
"authenticity_token"=>"XZ71eV0zxrnTBilzvEtLlHLwoAb+qKdDfxOHjrAHUPg=",
"participation"=>
{
"language_preference"=>"Türkçe",
"exam_center_preference"=>"1",
"disability"=>"1",
"user_id"=>"1",
"examination_id"=>""
},
"commit"=>"Sınava Başvur",
"examination_id"=>"1"
}
routes.rb:
resources :examinations do
resources :participations do
member do
get :update_profile_information
end
end
end
participation.rb:
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :examination
before_save :verification_key_generator
end
participations_controller.rb:
class ParticipationsController < ApplicationController
before_filter :authenticate_user!
before_action :set_participation, only: [:show, :edit, :update, :destroy]
before_filter :get_examination
def get_examination
#examination = Examination.find(params[:examination_id])
end
def index
#participations = #examination.participations
end
def show
#participation = #examination.participations.find(params[:id])
end
def new
#participation = Participation.new
end
def create
#participation = #examination.participations.new(participation_params)
#participation.user = current_user
respond_to do |format|
if #participation.save
format.html { redirect_to [#examination, #participation], notice: 'Başvuru işlemi başarıyla tamamlandı!' }
format.json { render action: 'show', status: :created, location: [#examination, #participation] }
else
render 'new'
format.html { render action: 'new' }
format.json { render json: #participation.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #participation.update(participation_params)
format.html { redirect_to [#examination, #participation], notice: 'Başvurunuz Başarıyla Güncellendi!' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: participation.errors, status: :unprocessable_entity }
end
end
end
private
def set_participation
#participation = Participation.find(params[:id])
end
def participation_params
params.require(:participation).permit(:user_id, :examination_id, :payment_status, :language_preference, :exam_center_preference, :disability)
end
end
app/views/participations/_form.html.erb:
<%= simple_form_for([#examination, #participation], html:{class: "well"}) do |f| %>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.input :language_preference, collection: ["Türkçe", "İngilizce", "Rusça"], label: 'Sınav Dili Tercihi' %>
<%= f.input :exam_center_preference, collection:ExamCenter.all, label: 'Sınav Merkezi Seçiniz', label_method: :city %>
<%= f.input :disability, inline_label: 'Yardımcı İstiyorum', label: false %>
<%= f.button :submit, "Sınava Başvur" %>
<% end %>
app/views/participations/new.html.erb:
<%= simple_form_for([#examination, #participation]) do |f| %>
<%= f.error_notification %>
<%= f.input :language_preference, collection: ["Türkçe", "İngilizce", "Rusça"], label: 'Sınav Dili Tercihi' %>
<%= f.input :exam_center_preference, collection:ExamCenter.all, label: 'Sınav Merkezi Seçiniz', label_method: :city %>
<%= f.input :disability, inline_label: 'Yardımcı İstiyorum', label: false %>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.button :submit, "Sınava Başvur" %>
<% end %>
sa
When you're using
<%= simple_form_for([#examination, #participation], html:{class: "well"}) do |f| %>
to generate the form, it will set the action to be /examinations/[examination_id]/participations so the routes/action will know the examination_id from the url itself.
So, you don't need to pass examination_id separately as hidden field that you're setting as
<%= f.input :examination_id, as: :hidden %>
Once you remove this hidden field the request parameters will look like:
{"utf8"=>"✓",
"authenticity_token"=>"XZ71eV0zxrnTBilzvEtLlHLwoAb+qKdDfxOHjrAHUPg=",
"participation"=>
{
"language_preference"=>"Türkçe",
"exam_center_preference"=>"1",
"disability"=>"1",
"user_id"=>"1"
},
"commit"=>"Sınava Başvur",
"examination_id"=>"1"
}

Resources