#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:.
Related
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.
I'm creating an admin interface where the admin (of a company) can add custom fields to their employees.
Example:
Models:
Employee: Basic info like name, contact info, etc (has_many employee_field_values)
EmployeeFields: These are the dynamic ones the admin can add (every company has different needs, it could be anything), lets say favorite_food
EmployeeFieldValues: The actual values based on the fields above, say pizza (belongs_to both models above)
What's a smart way of adding the EmployeeFieldValues fields while editing an employee?
I'm trying something simple like this, but not sure if I like it
# Controller
#custom_fields = EmployeeFields.all
# View
<%= form_for(#employee) do |f| %>
<%= f.text_field :first_name %>
<% #custom_fields.each do |custom_field| %>
<%= custom_field.name %>
<%= text_field_tag "employee_field_values[#{custom_field.name}]" %>
<% end %>
<%= f.submit :save %>
<% end %>
And then when updating, params[:employee_field_values] gives this:
<ActionController::Parameters {"favorite_food"=>"pizza"}>
So, not sure if this is a good direction, also I'm not sure how to handle future edits to an employee's custom_fields if they change.
I think it will be better to use EmployeeField as nested model and EmployeeFieldValue for select field.
For example:
Models
class Employee < ActiveRecord::Base
validates :name, presence: true
has_many :employee_field_values
accepts_nested_attributes_for :employee_field_values, reject_if: ->(x) { x[:value].blank? }
end
class EmployeeFieldValue < ActiveRecord::Base
belongs_to :employee
belongs_to :employee_field
end
class EmployeeField < ActiveRecord::Base
has_many :employee_field_values, inverse_of: :employee_field, dependent: :destroy
validates :title, presence: true, uniqueness: true
end
Controller
class EmployeesController < ApplicationController
def new
#employee = Employee.new
#employee.employee_field_values.build
end
end
View
= simple_form_for #employee, url: '/' do |f|
= f.input :name
= f.simple_fields_for :employee_field_values do |ff|
= ff.input :value
= ff.input :employee_field_id, collection: EmployeeField.all.map{|x| [x.title, x.id]}
Also you need to make buttons for adding/removing :employee_field_value, and you can do it with gem cocoon for example
OR you can build all objects in controller(for each EmployeeField) and do without select box
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}) %>
I want to create a form that has nested attributes, which populates a record within a rich join table. (That created record within the rich join table of course should have the appropriate foreign keys.)
I have yet to find a thorough answer on creating nested form fields on a has_many :through relationship. Please help!
For this example, I have a user form. Within that form, I am also trying to populate a record within the users_pets table (rich join table).
Additional question: are rich join models supposed to be singular or plural? Example: app/models/owners_pets.rb or app/models/owners_pet.rb.
app/models/owner.rb
class Owner < ActiveRecord::Base
has_many :owners_pets, allow_destroy: true
has_many :pets, through: :owners_pets
end
app/models/pet.rb
class Pet < ActiveRecord::Base
has_many :owners_pets, allow_destroy: true
has_many :owners, through: :owners_pets
end
app/models/owners_pets.rb
class OwnersPet < ActiveRecord::Base
belongs_to :owners
belongs_to :pets
end
app/controller/owners.rb
def owner_params
params.require(:owner).permit(:first_name, owners_pets_attributes: [:id, :pet_name, :pet_id])
end
app/views/owners/_form.html.erb
<%= simple_form_for(#owner) do |f| %>
<%= f.input :first_name %>
<%= f.simple_fields_for :owners_pets do |ff|
<%= ff.input :pet_name %>
<% end %>
<div>
<%= f.button :submit %>
</div>
<% end %>
Here is the answer, thanks to a bunch of help from a mentor. It helps me to keep in mind that rich join naming conventions should NOT be pluralized at the very end, just like other non-rich-join models. Ex: book_page.rb NOT books_pages.rb. Even books_page.rb would work (just update your strong params and database table accordingly). The important part is that the entire model must follow the rails convention of the model being singular (no 's' on the end).
Below in the rich join model, I made the decision to name it the completely singular version: owner_pet.rb as opposed to the other version: owners_pet.rb. (Therefore of course, my database table is named: owner_pets)
app/models/owner.rb
class Owner < ActiveRecord::Base
has_many :owner_pets
has_many :pets, through: :owner_pets
accepts_nested_attributes_for :owner_pets, allow_destroy: true
end
app/models/pet.rb
class Pet < ActiveRecord::Base
has_many :owner_pets
has_many :owners, through: :owner_pets
end
app/models/owner_pet.rb
class OwnerPet < ActiveRecord::Base
belongs_to :owner
belongs_to :pet
end
app/controller/owners.rb
def new
#owner = Owner.new
#owner.owner_pets.build
end
private
def owner_params
params.require(:owner).permit(:first_name, owner_pets_attributes: [:_destroy, :id, :pet_name, :pet_id, :owner_id])
end
app/views/owners/_form.html.erb
<%= simple_form_for(#owner) do |f| %>
<%= f.input :first_name %>
<%= f.simple_fields_for :owner_pets do |ff| %>
<%= ff.input :pet_name %>
<%= ff.input :pet_id, collection: Pet.all, label_method: "pet_type" %>
<% end %>
<div>
<%= f.button :submit %>
</div>
<% end %>
Your join table is the problem:
It should be belongs_to :owners belongs_to :pets for the join table to work
Plus the rich join model should be pluralised, as in: owners_pets
I'm trying to build a rather complex nested form in rails and am stuck.
Basically, I have three models - Applicant, DataPoint, ApplicantDataPointValue .
The user can create a new DataPoint, give it a name ("gender" etc.) select it's type ("string","integer" etc.). The type determines what column the data will eventually be saved in in the ApplicantDataPointValue table.
I then want the user, when they're creating a new Applicant, to be able to add a value for each DataPoint into the ApplicantDataPointValue table
My models look like the following:
Applicant:
class Applicant < ActiveRecord::Base
has_many :applicant_data_point_values, dependent: :destroy
has_many :data_points, :through => :applicant_data_point_values
accepts_nested_attributes_for :data_points
accepts_nested_attributes_for :applicant_data_point_values
attr_accessible :data_points_attributes, :applicant_data_point_values_attributes
end
DataPoint:
class DataPoint < ActiveRecord::Base
has_many :applicant_data_point_values
has_many :applicants, :through => :applicant_data_point_values
accepts_nested_attributes_for :applicant_data_point_values
end
ApplicantDataPointValue:
class ApplicantDataPointValue < ActiveRecord::Base
belongs_to :data_point
belongs_to :applicant
end
But I'm at a loss to what to do in the 'new' and 'create' sections of my controller or how to construct the form.
Any insight would be greatly appreciated.
From what I understand, the form for the User will also have multiple ApplicantDataPointValue fields. (but that form won't allow creating of new DataPoint fields, right?)
In the controller new action, you'll want to set up your model with associated data point values:
def new
#user = User.new
DataPoint.all.each do |data_point|
applicant_data_point_value = #user.applicant_data_point_values.build
applicant_data_point_value.data_point = data_point
end
end
And then, display a text box for each data point value.
<%= form_for #user do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<% #user.applicant_data_point_values.each do |data_point_value| %>
<%= f.fields_for :applicant_data_point_values, data_point_value do |fields| %>
<%= fields.label :value, data_point_value.data_point.type %>
<%= fields.text_field :value %>
<% end %>
<% end %>
Reference: http://railscasts.com/episodes/196-nested-model-form-part-1