Rails collection_select form adds selected value to an array - ruby-on-rails

I have a Rails 4 app that is a game database. The models relevant to this question are:
Game
Genre
GameGenre (the relationship table)
It has a games/new form, which creates new game records.
Within that form, I want a sub-form which allows the user to add genres. I envision it working as follows:
The user selects a genre from the select input. The options are populated from Genre.all
When the user hits the Add button, the id of the selected genre is pushed to an array. They can add as many genres as they want to this array.
When the user hits Save on the main game form, the app uses an add_genre function I've defined to create GameGenre relationship records for each of the genres.
This is my games/new.html.erb view code at present:
<div id="game-genres-form">
<%= fields_for(#game.game_genres.build) do |f| %>
<div><%= hidden_field_tag :game_id, #game.id %></div>
<div class="form-group">
<%= f.label :genre_id, "Add a genre" %>
<div class="input-group">
<%= f.collection_select :genre_id, Genre.all, :id, :name,
{}, {:class=>'form-control'} %>
<span class="input-group-btn">
<%= f.submit "Add", class: "btn btn-default" %>
</span>
</div>
<% end %>
</div>
This does not work, because fields_for(#game.game_genres.build) is incorrect. In fact, at present when I click 'Add' it submits the new-game form and creates a game record but doesn't add the genre.
I think what I need to know is, what do I use instead of fields_for(#game.game_genres.build) to pass the submitted genre to a new array? And how can I set up this up in games_controller.rb?
I realise <div><%= hidden_field_tag :game_id, #game.id %></div> won't be necessary (since game_id doesn't exist until the new game record has been saved).
I hope I'm making sense, thanks for the help.
These are my current associations, they are missing accepts_nested_attributes_for. I'm not too worries about this at the moment - I mainly want to know the right type of form to use, and how to make it add each genre to a hash/array.
class Game < ActiveRecord::Base
belongs_to :user
has_many :game_genres, foreign_key: :game_id,
dependent: :destroy
has_many :genres, through: :game_genres
class GameGenre < ActiveRecord::Base
belongs_to :game
belongs_to :genre
class Genre < ActiveRecord::Base
belongs_to :user
has_many :game_genres, foreign_key: :genre_id,
dependent: :destroy
has_many :games, through: :game_genres

May be you are missing something like this in your game model
accepts_nested_attributes_for :game_genres ,allow_destroy: true
or you can try this to save your genres in your view
<%= collection_select(:category, :ids, Category.all, :id, :category, { :selected => #categories.map{|m| m.id}}, {:multiple=>true}) %>

Related

Display rails join table field

So I am making an edit page that can edit animals and the owners to that animal. There is a join table involved which contains what Animal belongs to what Owner.
More precisely, Say you have:
<% form_for :animal, url: animal_path(#edit_animal), method: :patch do |edit| %>
... animal labels and fields to edit go here ...
<%= edit.fields_for :owners do |owner| %>
<%= owner.label :name, "Name" %>
<%= owner.text_field :name %>
<%end%>
<%=edit.submit 'Submit'%>
<%end%>
Model Associations:
AnimalOwner < ApplicationRecord
belongs_to :animal
belongs_to :owner
Owner < ApplicationRecord
has_many :animal_owners
has_many :animals, :through => :animal_owners
Animal < ApplicationRecord
has_many :animal_owners
has_many :owners, :through => :animal_owners
Basically, I am not sure if I am doing the form correctly for join tables. I also wanted to be able to display the data currently saved in the database using :value, but what how I would do that for a join table?
<%= owner.text_field :name, :value => what_goes_here? %>
If you are doing the Rails way, you don't need to mention the value for existing database data.
<%= owner.text_field :name%>
This should populate the data to above given field. Also its always better to use a single for for both "new" and "edit" methods. And for "edit" you can also use "PUT" as method type.
To use the field_for tag, you will also need to tell your Animal model that it accepts_nested_attributes_for :owners. This will allow the nested params to be massed assigned to the Animal instance.

Why does new select form increase?

#post.post_tags.build
the above is posts contorller(post_tags is intermediate table between posts and tags) and view is like this.
<div class="form-group">
<%= f.fields_for :post_tags do |pt| %>
<%= pt.select :tag_id, #tags.map{|t| [t.name, t.id]}, { :prompt => "choose name", label: "tag" }, class: "tag-fields" %>
<% end %>
</div>
When I edit a post, tags related to the post show correctly but new select box with "choose name" is also created. I don't want the new select box and I don't know why select box is created.
How should I fix it?
Thanks,
Ken
When using indirect relationships don't focus on the joining models. ActiveRecord will create them for you.
Lets say you have:
class Post < ApplicationRecord
has_many :tags, through: :taggings
end
class Tag < ApplicationRecord
has_many :posts, through: :taggings
end
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :post
end
This will let us tag a post by:
#post.tags < #tag
Or create a tag by:
#post.tags.create(name: '#yolo')
If you want to create a select tag or checkboxes where a user can choose tags use the collection helpers:
<%= form_for(:post) do |f| %>
<%= f.collection_check_boxes :tag_ids, Tag.all, :id, :name %>
<% end %>
The special relation_name_ids setters can create/destroy associations on the fly from an array of ids. The best thing is that Rails will handle joining for you when you use HABTM or has_many through:.

How can I display only a range of values in a rails form view?

I'm quite new to rails and I have some problem with views...I have among others these three models : reservation,route and stop.
When you make a reservation, you have to select the route and the city of departure/arrival.
EDIT
class Route < ActiveRecord::Base
has_many :stops, :dependent => :destroy
has_many :reservations, :dependent => :destroy
belongs_to :train
end.
class Stop < ActiveRecord::Base
belongs_to :route
has_many :reservation_deps, class_name: "Reservation", foreign_key: "dep_city_id"
has_many :reservation_arrs, class_name: "Reservation", foreign_key: "arr_city_id"
end
class Reservation < ActiveRecord::Base
belongs_to :user
belongs_to :route
belongs_to :arr_city, class_name: "Stop",foreign_key: "arr_city_id"
belongs_to :dep_city, class_name: "Stop",foreign_key: "dep_city_id"
end
I don't know if it is possible but I'd like to be able to select my city of departure/arrival only among those that belong to the route I've chosen. Any ideas how to do that?
Thank you!
Below there's a part of my reservation's form:
<div class="field">
<%= f.label :route %><br>
<%= f.collection_select(:route_id,Route.all,:id,:as_field) %><br>
</div>
<div class="field">
<%= f.label :departure_city %><br>
<%= f.collection_select(:dep_city_id,Stop.all,:id,:city) %><br>
</div>
<div class="field">
<%= f.label :arrival_city %><br>
<%= f.collection_select(:arr_city_id,Stop.all,:id,:city) %><br>
</div>
Your stops should be linked to your routes through a has_and_belongs_to or has_many :through relationship right, since routes can contain many stops, and stops can belong to many routes. So assuming you have a route loaded on your reservations page, you should be able to just do the following
<%= f.collection_select :dep_city_id, #route.stops.all, :id, :name %>
<%= f.collection_select :arr_city_id, #route.stops.all, :id, :name %>
Alternatively something like
Edit: This will work even if the route to stops relationship is one to many.
<%= f.collection_select :dep_city_id, Stop.for_route(params[:route_id]), :id, :name %>
Edit 2:
In this case, it is expected that you have added a for_route scope to your Stop model which would just be a
scope for_route -> (route_id) { where(:route_id => params[:route_id]) }
In the basic case, you would have a page with your routes, you pick a route (link or something), and are taken to a page where you can make a reservation. The first page would have something like this
<% #routes.each do |route| %>
<%= link_to route.name, new_reservation_path(:route_id => route.id) %>
<% end %>
The links generated by the code above should link to something like /reservation?route_id=XXX
When the reservations_controller#new is run, you know what the route ID is, so you can load it with something like #route = Route.find(params[:route_id])
Then, when rendering the page you will be able to use the f.collection_select helper I specified in the first example code.
In the last case, where you dont know what route the user will pick until they have selected one on the reservations page, it gets more complicated, and you will have to start using JS to query get a list of stops a route every time a new route is chosen.

collection_select not filtering (in nested_form w/nested resources)

I've got an application that uses nested resources (see routes.rb below) to completely segregate users. It works great until I use collection_select to allow users to select objects from other models. For example, if I visit the store index view as user A, I only see stores created by user A. However, if I visit the store_group view and try to select a store to add to the group from the collection_select menu under the fields_for :store_group_details, I see all stores created by all users.
As far as I can tell, the problem might happen because there is no filter for stores in the store_group controller. store_group_details doesn't have a controller, but from what I've read, that seems to be correct since the model can only be accessed through a nested form in the store_group view. I have another situation where another view for another resource has several collection_select menus for selecting objects from other models, and all of those have the same problem (they display all objects in that model, regardless of which user created them).
How can I filter the objects shown in the collection_select menus? Is it a problem with what I'm passing into collection_select, or is it because the controllers don't do anything to filter the other models before those models' objects are displayed? I've looked at the docs for collection_select, and couldn't make it work based on that.
Thanks for your help, I've spent quite a bit of time trying to get this to work.
user.rb
class User < ActiveRecord::Base
has_many :store_groups
has_many :stores
has_many :store_group_details
end
store.rb
class Store < ActiveRecord::Base
belongs_to :user
has_many :store_group_details
has_many :store_groups, :through => :store_group_details
end
store_group.rb
class StoreGroup < ActiveRecord::Base
belongs_to :user
has_many :store_group_details, :inverse_of => :store_group
has_many :stores, :through => :store_group_details
accepts_nested_attributes_for :store_group_details
attr_accessible :store_group_details_attributes
end
store_group_detail.rb
class StoreGroupDetail < ActiveRecord::Base
belongs_to :store
belongs_to :store_group
belongs_to :user
attr_accessible :store_id
delegate :store_name, :to => :store
end
_store_group_form.html.erb
<div class="container">
<div class="span8">
<%= nested_form_for([#user, #store_group]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label "Store Group Name (required)" %>
<%= f.text_field :store_group_name %>
<%= f.label "Store Group Description" %>
<%= f.text_area :store_group_description %>
<%= f.fields_for :store_group_details %>
<p><%= f.link_to_add "Add store to group", :store_group_details %></p>
<br>
<%= f.submit "Submit", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
_store_group_detail_fields.html.erb
<p>
<%= f.label "Select Store:" %>
<%= f.collection_select :store_id, Store.order(:store_name),
:id, :store_name, include_blank: true %>
<%= f.link_to_remove "remove" %>
</p>
routes.rb
resources :users do
resources :stores
resources :store_groups
resources :store_group_details
end
There must be a problem with your controller. Did you ever solve this issue?
Look at this answer as it might lead to a solution. Or add you stores_controller.rb.

How to return appropriate nested attribute value in a form (edit action)?

I have following structure:
class Project < ActiveRecord::Base
has_many :costs, :dependent => :destroy
accepts_nested_attributes_for :costs, :allow_destroy => true
end
class Cost < ActiveRecord::Base
belongs_to :project
end
Suppose there are two attributes in Cost model: cost_plan (used in new action) and cost_fact (properly used in edit). I'm tying to do something like this when editing form:
<!-- _cost_fields.erb -->
<div title="<%= value of :cost_plan %>">
<%= f.label :cost_fact %>
<%= f.text_field :cost_fact %>
</div>
I can return value of :cost_plan using hidden_field, but how to return it as title text?
Just get the object of the form helper back and retrieves it's associated objects directly:
<%= f.object.attribute %>
<%= f.object.costs.first.attribute %>

Resources