many to many form, mongoid & rails 3 - ruby-on-rails

I have 2 models in my app. A Shopping_list and a Product
The shopping list can contain many products, a product can be a part of many shopping lists.
The shopping list -
class Shopping_list
include Mongoid::Document
field :name, :type => String
has_and_belongs_to_many :products
end
And the product
class Product
include Mongoid::Document
field :name, :type => String
has_and_belongs_to_many :shopping_lists
end
If a user visits /shopping_list/some_id/edit I want them to see -
a) The name of the product in a text box
b) A series of checkboxes listing all of the products that they can check to add to that list.
c) A submit button.
My controller looks like this
def edit
#shopping_list = Shopping_list.find(params[:id])
render :action => 'edit'
end
My view looks like this
<%= simple_form_for(#shopping_list) do |f| %>
<%= f.input :name %>
<%= f.input :articles, :as => :check_boxes %> #I know this is completely wrong. What do I do to fix?
<%= f.button :submit %>
<% end %>
This does not work at all and I'm a bit stumped. Not sure how to proceed while using Mongoid.
Advice appreciated.

try this
<%= simple_form_for(#shopping_list) do |f| %>
<%= f.input :name %>
<%= f.association :products,:collection => #shopping_list.products.collect{ |p| [p.name, p.id] }, :as => :check_boxes %>
<%= f.button :submit %>
<% end %>

Related

Setup Rails Form Builder for Related Resource

I do not understand how to setup forms with related resources in Rails 4.
My models:
class Task < ActiveRecord::Base
belongs_to :category
accepts_nested_attributes_for :category
end
class Category < ActiveRecord::Base
end
I'm trying to setup a form where I can simply select the "category" from a drop down box.
How do I setup my controller and form view to accomplish this?
Try this:
<%= form_for #task do |f| %>
<%= f.collection_select :category_id, Category.all, :id, :name, {}, { :multiple => false } %>
<% end %>
This assumes you have an attribute in your Category model called name.
Add category_id to your strong parameters in your Tasks Controller.
An example with and without simple_form
<%= simple_form_for #object do |f| %>
<%= f.input :name %>
<%= f.association :company %>
<%= f.button :submit %>
<% end %>
And without sf
<%= form_for #object do |f| %>
<%= f.collection_select :company_id, Company.all, :id, :name =>
<% end %>
Both will produce a dropdown of company's using the name in the select list.

How to always select the created field when entering data into anther model?

So right now in the following app, you create an event and then you get forwarded to enter student number page(another model).
I want to be able to create and event and then able to add student number to that event, without needing to select the event.
The Student and Event controllers don't have anything different. I used what the scaffold command generated.
This is the Event Model:
class Event < ActiveRecord::Base
has_many :students
end
This is the form for Events:
<%= semantic_form_for #event do |f| %>
<%= f.inputs do %>
<%= f.input :name %>
<%= f.input :description %>
<% end %>
<%= f.actions do %>
<%= f.action :submit, :as => :input %>
<% end %>
<% end %>
This is the Students Model:
class Student < ActiveRecord::Base
validates :studentnumber,
numericality: { only_integer: true },
length: { is: 8}
belongs_to :event
end
This is the form for Students:
<%= semantic_form_for #student do |f| %>
<%= f.inputs do %>
<%= f.input :event, :label => "Select Your Event", :include_blank => false %>
<%= f.input :studentnumber, :label => "Student Number", :input_html => { :autofocus => true} %>
<% end %>
<%= f.actions do %>
<%= f.action :submit, :as => :input %>
<% end %>
<% end %>
Right now when I create an event I have it forward me to the Students page and the created event is shown as a dropdown. Thus, to create a student I have to select the event and then hit submit.
I would like to always select the created event and event student-numbers in that event. How can I accomplish this?
You could use nested resources in your route configuration for that:
resources :events do
resources :students
end
This gives a new route for students like this: /events/:event_id/students/new. You can then redirect in your events controller after creating an event to the new action:
def create
#event = Event.create(params[:event])
if #event.save
redirect_to new_event_student_path(#event)
else
render :edit
end
end
In your students controller you simply need to fetch the associated event. Since all students belong to an event, you can do it in a before filter. In your new action you instantiate a new student and assign the event to it:
class StudentsController < ApplicationController
before_filter :fetch_event
def new
#student = Student.new(:event => #event)
end
private
def fetch_event
#event = Event.find(params[:event_id])
end
end
In the student's new view the correct event should be automatically selected and you can change the event input field to be hidden.
Better on the other hand would be to drop the event input field and change the form URL to be the create route of the nested resource: event_students_path(#event)
For more information on routing in Rails, see http://guides.rubyonrails.org/routing.html#nested-resources
You don't even need to send it other form. You should use accept nested attributes in Rails.
Add this in your event model
class Event < ActiveRecord::Base
has_many :students
accept_nested_attributes_for :students
end
And in your Event controller new action
def new
#event = Event.new
#event.students.build
end
And in your event creation form, include your students form like this:
<%= semantic_form_for #event do |f| %>
<%= f.inputs do %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.fields_for :students do |s|
<%= s.input :studentnumber, :label => "Student Number" %>
<% end %>
<% end %>
<%= f.actions do %>
<%= f.action :submit, :as => :input %>
<% end %>
<% end %>
Hope it will help. Thanks

Nested Form: Resource adds dynamically but doesnt get created?

I am using the nested form gem and i add products dynamically to the form. When i do click "add", another product resource appears but on creation it ERASES the former ones from being created entirely. This is how the scenario goes:
Fill in Location
Choose Date
Fill in Product ( one is already on form)
Add 5 more products (Products 2, 3, 4, 5)
Fill in All Products
"click" Create
Created Product 5
This is how my nested form looks:
<%= nested_form_for #location, :url => products_path(#product) do |f| %>
<%= f.label :business %>
<%= f.text_field :business %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.fields_for :product_dates, :url => products_path(#product) do |d| %>
<%= d.label :date %>
<%= d.date_select :date %>
<%= d.fields_for :products, :url => products_path(#product) do |p| %>
<%= p.text_field :name %>
<%= p.text_field :price %>
<%= p.text_field :tag_list %>
<%= p.link_to_remove "Remove Product" %>
<% end %>
<%= d.link_to_add "Add", :products %>
<% end %>
<%= f.submit "Finish" %>
<% end %>
Controller:
class ProductsController < ApplicationController
def new
#location = Location.new
#product = Product.new
product_date = #location.product_dates.build
product_date.products.build
end
def create
#location = Location.create(params[:location])
if #location.save
flash[:notice] = "Products Created."
redirect_to :action => 'index'
else
render :action => 'new'
end
end
Models:
class User < ActiveRecord::Base
devise
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :products, :dependent => :destroy
end
class Location < ActiveRecord::Base
attr_accessible :address, :business, :product_dates_attributes
has_many :products
has_many :product_dates
accepts_nested_attributes_for :product_dates
end
class ProductDate < ActiveRecord::Base
attr_accessible :date, :products_attributes
belongs_to :location
belongs_to :user
has_many :products
accepts_nested_attributes_for :products
end
class Product < ActiveRecord::Base
attr_accessible :name, :price, :tag_list
belongs_to :user
belongs_to :location
belongs_to :product_date
end
Any Suggestions?
First of all remove the url_for declarations on the fields_for declarations so you get
<%= nested_form_for #location, :url => products_path(#product) do |f| %>
<%= f.label :business %>
<%= f.text_field :business %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.fields_for :product_dates do |d| %>
<%= d.label :date %>
<%= d.date_select :date %>
<%= d.fields_for :products do |p| %>
<%= p.text_field :name %>
<%= p.text_field :price %>
<%= p.text_field :tag_list %>
<%= p.link_to_remove "Remove Product" %>
<% end %>
<%= d.link_to_add "Add", :products %>
<% end %>
<%= f.submit "Finish" %>
<% end %>
What is really confusing is your whole routing and params approach. It's just not right. You have a form_for #location with a :url products_path(#product) This will right royally cause issues with the params that are sent back and there in lies the problem.
Stick with routing to location controller not the products controller by removing the products_path(#product) form your nested_form_for declaration and you will find that you will have all the necessary records saved but you will most likely need to change the redirect_to declaration in the locations_controller create action and the same for the update_action.
But why use the products controller at all when you are dealing with a location? Again this just isn't natural or intuitive.
One last thing. Your remove links won't work as you have not added the necessary :dependent => :destroy declaration to the has_many declarations and you are also missing the :reject_if procs and the :allow_destroy => true declarations on the accepts_nested_attributes declarations.
Can I strongly suggest that you
1) Use either the locations controller or the products controller not both
I mean link to get to this form link_to the locations controller and set everything up there or use form_for #product rather than #location and handle everything in the products controller
2) watch the railscasts that this gem is based on very closely
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
3) Spend some time learning about how rails form view helpers arrange for the params hash to be organised in the controllers actions. In your case, have a close look at your log file for the parameters that come into the create action as things currently stand.
You will most likely see that the params are not nested as you would exect them to be which is why the nested attributes declaration is not behaving as expected

Formtastic: how to choose what method to run on a collection to determine the label when using model associations?

I have the following two simple models for users and user groups:
class User < ActiveRecord::Base
belongs_to :user_group
end
and
class UserGroup < ActiveRecord::Base
has_many :users
end
I use the following formtastic code to draw my form for the UserGroup model:
<% semantic_form_for [:system, #user_group] do |form| %>
<% form.inputs do %>
<%= form.input :name %>
<%= form.input :description %>
<%= form.input :users, :as => :check_boxes %>
<% end %>
<% form.buttons do %>
<%= form.commit_button "Save Group" %>
<% end %>
<% end %>
The form displays nicely and lists all Users in the system with checkbox checked for the users that currently belong to the UserGroup. Currently, the only attribute of the user in the list that it displays is the "username".
How is it determining to use the "username" method to get the label for each user?
How do I change it to show the "first_name" and "last_name" attributes?
Thanks
Looks like this is accomplished through formtastic's :label_method. Found in this answer.
<%= form.input :users, :label_method => :username, :as => :check_boxes %>
or
<%= form.input :users, :label_method => Proc.new { |x| "#{x.first_name} #{x.last_name}" }, :as => :check_boxes %>

Formtastic Confused on Has One Relationships

I'm a bit stuck on a 'has_one' and 'belongs_to' relationship and getting it to properly display in Formtastic. I have a person model that has one picture (a profile picture). I want the user to be able to select the picture using radio buttons. So far, I have:
<% form.inputs do %>
<%= form.input :picture, :as => :radio, :collection => #pictures %>
<% end %>
However, this fails (because the foreign key is stored on the 'belongs_to' side of associations in Rails. Any suggestions?
Ended up using custom controller code to fix. Use a variety of filters, etc.
Came across this in the "related" sidebar. I think this is a good use case for nested attributes -- from the Formtastic README:
Nested forms are also supported (don’t forget your models need to be setup correctly
with accepts_nested_attributes_for). You can do it in the Rails way:
<%= semantic_form_for #post do |form| %>
<%= form.inputs :title, :body, :created_at %>
<%= form.semantic_fields_for :author do |author| %>
<%= author.inputs :first_name, :last_name, :name => "Author" %>
<% end %>
<%= form.buttons %>
<% end %>
Or the Formtastic way with the :for option:
<%= semantic_form_for #post do |form| %>
<%= form.inputs :title, :body, :created_at %>
<%= form.inputs :first_name, :last_name, :for => :author, :name => "Author" %>
<%= form.buttons %>
<% end %>

Resources