I'm building an open-source spreadsheet application. So far, its a rails application that has 4 models: table, row, column, and item.
Here is what they look like:
Table.rb:
has_many :columns
has_many :rows
accepts_nested_attributes_for :columns
Column.rb
belongs_to :table
has_many :items
Row.rb
belongs_to :table
has_many :items
accepts_nested_attributes_for :items
Item.rb
belongs_to :row
On the page where you add a new row. You should be presented with something like this:
So the columns are already set, so now you are adding new items which when inserted should include the row_id, column_id, and value for each item.
So far my form looks like this:
<%= nested_form_for [#table, #row] do |f| %>
<% #columns.each do |column| %>
<%= column.name %> <br>
<%= f.fields_for :items do |item_form| %>
<%= item_form.text_field :value %>
<% end %>
<% end%>
<%= f.submit %>
<% end %>
I'm using the nested_form for the nested forms. But so far, I can't get a textbox for the item's value to show up. Also, is this the best way to get what I want (like the picture), or is there a cleaner way?
Thanks for all help!
You'll need to build at least 1 item for fields_for to render anything. Try doing this in your new controller action.
def new
...
#row.items.build
end
Related
So im working through the Odin Project's "Flight Booker" project. https://www.theodinproject.com/courses/ruby-on-rails/lessons/building-advanced-forms. Which essentially is what it sounds like and im running into a problem with passing nested attributes.
First and foremost the Relevant Models:
class Booking < ApplicationRecord
belongs_to :passenger
belongs_to :flight
accepts_nested_attributes_for :passenger
end
class Flight < ApplicationRecord
has_many :bookings, dependent: :destroy
has_many :passengers, through: :bookings
belongs_to :to_airport, class_name: 'Airport', foreign_key: 'origin_id'
belongs_to :from_airport, class_name: 'Airport', foreign_key: 'destination_id'
end
class Passenger < ApplicationRecord
has_many :bookings, dependent: :destroy
has_many :flights, through: :bookings
end
The passenger schema just contains an email and name for right now. But the problem is when I pass the information to the "booking" controller. Here is my "New" form for booking.
<%= form_for #booking do |f| %>
<%= f.hidden_field :flight_id, value: params[:booking][:flight_num] %>
<%= f.hidden_field :passengers_num, value: params[:booking][:passengers_num] %>
<% params[:booking][:passengers_num].to_i.times do |passenger| %>
<%= fields_for :passenger do |passenger| %>
<%= passenger.label :name, 'Name', class: "Label" %>
<%= passenger.text_field :name %>
<%= passenger.label :email, 'email', class: "Label" %>
<%= passenger.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Book Flight" %>
<% end %>
(Ignore the hidden fields for now, they are passed from the "Flights" search page and Im getting those just fine.)
So I am getting the multiple forms (name and email fields) but when I "Submit" I am only getting parameters for the last field sets. (So if there are 3 sets of name/email fields, I only get parameters for the last one).
It's possible im not understanding the fields_for however as I can't find a ton of good examples.
Thanks!
There could be many issues with your implementation...I'll layout a few...
Move <% params[:booking][:passengers_num].to_i.times do |passenger| %> logic into the new action of your bookings controller...ie
def new
#booking = Booking.new
3.times { #booking.passengers.new } # or whatever your logic is to display x amount of passenger fields
end
Make sure that in your bookings controller you are permitting the nested attributes like this...
params.require(:booking).permit(passengers_attributes: [:name, :email])
As far as the form, you'll need to treat it like a form within a form (makes sense...nested attributes created from a nested form!) and use the block variable...like this
<ul>
<%= f.fields_for :passengers do |passenger_form| %>
<li>
<%= passenger_form.label :name
<%= passenger_form.text_field :name %>
</li>
<!-- other permitted fields -->
<% end %>
</ul>
I can't figure this out for the life of me but here are my models:
class User < ApplicationRecord
has_many :user_stores
has_many :stores, through: :user_stores
end
class UserStore < ApplicationRecord
belongs_to :user
belongs_to :store
end
class Store < ApplicationRecord
has_many :user_stores
has_many :users, through: :user_stores
end
So I have a join table, I'm trying to make a form, which would have selected checkboxes next to the store names that the user has selected (this information would come from the join table relationship) and open checkboxes for the remaining stores (coming from the Store model). How do I show that in the view/make it work in the controller as well. Would I use collections instead? ( I am using Devise and Simple Form gem )
This is what I have so far:
<h1>Add Favorite Stores</h1>
<%= simple_form_for(#user, html: { class: 'form-horizontal' }) do |f| %>
<%= f.fields_for :stores, #user.stores do |s| %>
# not sure if this is the right way or not
<% end %>
<%= f.button :submit %>
<% end %>
Store Controller:
class StoresController < ApplicationController
...
def new
#user = current_user
#stores = Store.all
# #user.stores => shows user's stores (from join table)
end
end
When you set up a one or many to many relationship in rails the model gets a _ids setter:
User.find(1).store_ids = [1,2,3]
This would for example setup a relation between user 1 and the stores with ids 1,2 and 3.
The built in Rails collection form helpers make use of this:
<%= form_for(#user) do |f| %>
<% f.collection_check_boxes(:store_ids, Store.all, :id, :name) %>
<% end %>
This creates a list of checkboxes for each store - if an association exists it will already be checked. Note that we are not using fields_for since it is not a nested input.
SimpleForm has association helpers which add even more sugar.
<h1>Add Favorite Stores</h1>
<%= simple_form_for(#user, html: { class: 'form-horizontal' }) do |f| %>
<%= f.association :stores, as: :check_boxes %>
<%= f.button :submit %>
<% end %>
I'm on rails 4.
I have one model features that has a list of records only createable by me. I have another model houses that users can create.
I want to list all of the features as checkboxes in the form for a new house so the users can choose which ones they want attached to their house. I also have a connecting model house_features that associates the two because many houses can have many different features.
My house model:
has_many :house_features, dependent: :destroy
has_many :features, through: :house_features
accepts_nested_attributes_for :house_features
My feature model:
has_many :house_features
has_many :houses, through: :house_features
My house_feature model:
belongs_to :house
belongs_to :feature
In my new house form I have
<%= form_for #house do |f| %>
<% Features.all.each do |feature| %>
<%= f.fields_for :house_features do |h| %>
<%= h.label :feature_id, feature.name %>
<%= h.check_box :feature_id, {}, feature.id %>
<% end %>
<% end %>
<% end %>
In my houses controller I have a #house.house_features.build in my new action and I have the house_params set to `house_features_attributes: [:id, :house_id, :feature_id]
Now, on the new house page, The list of feature record checkboxes show up. If I select some and submit the form and then go back to edit the house, I end up having a bunch of extra checkboxes for each feature listed and the number of check boxes corresponds with the amount of features I chose when creating it.
Why is this happening? Would should I do/change to fix this issue?
I want my users to be able to edit their houses and add or remove features.
Thanks
Seems you have redundant loop:
<%= f.fields_for :house_features do |h| %>
You should rewrite your loops to use only one loop and select checkboxes which selected for this house:
<%= form_for #house do |f| %>
<% Features.all.each do |feature| %>
<%= h.label :feature_id, feature.name %>
<%= h.check_box :feature_id, {checked: #house.house_features.include?(feature)}, feature.id %>
<% end %>
<% end %>
I have 2 models, clients and client_prices, I would like to have 2 client prices nested forms sections in the client's show page. 1 nested form would be for non-custom prices and another for custom prices. The non-custom (custom == false) prices would only have the "custom" attribute available to edit. The "Custom Prices" would have all of the attributes available to edit.
I've tried a few different approaches, but I don't know where to put the conditional logic to make this work correctly. I'm using simple_form to generate the forms, but I'm not married to it.
Controllers
class Client < ActiveRecord::Base
attr_accessible :name, :client_prices_attributes
has_many :client_prices
accepts_nested_attributes_for :client_prices, :allow_destroy => true
end
class ClientPrice < ActiveRecord::Base
attr_accessible :client_id, :price, :visit_type, :id, :custom
belongs_to :client
belongs_to :default_price
end
Client Show page
<%= simple_nested_form_for #client do |f| %>
<%= f.fields_for :client_prices do |def_price_form| %>
non-custom prices form here
<%end%>
<%= f.fields_for :client_prices do |def_price_form| %>
custom prices form here
<%end%>
<%end%>
Try the following:
<%= simple_nested_form_for #client do |f| %>
<%= f.fields_for :client_prices do |def_price_form| %>
<%= if def_price_form.object.custom %>
Here you fields for custom form
<% end %>
<% end %>
<% end %>
I am trying to find a way to pull all notes that are assigned to a course but only when necessary. I have a show page which shows all of the notes for a quiz.
course show.html.erb
<%= #course.name %>
<% #quiz.notes.each do |note| %>
<%= link_to note.title, quiz_note_path(#quiz, note) %><br/>
<% end %>
The above code works find except it pulls all of the notes and not the notes that are assigned to that course. How can I tell rails to only pull the note if note and course name are equal?
update!
In the note new.html.erb I have am using collection_select
<%= f.collection_select(:course_ids, #quiz.courses, :id, :note_name, options = {:prompt => "Choose"}) %>
It seems like you don't have relationship between course and quiz.
A course has many quizzes, a quiz has many notes. You should setup your relationship this way, so it won't pull out unnecessary notes that are not related to the current course.
The trick here is to pull all notes inside a course by using has_many :through.
class Course < ActiveRecord::Base
has_many :quizzes
has_many :notes, :through => quizzes
end
class Quiz < ActiveRecord::Base
has_many :notes
end
class Note < ActiveRecord::Base
belongs_to :quiz
end
<%= #course.name %>
<% #course.notes.each do |note| %>
<%= link_to note.title, quiz_note_path(note.quiz, note) %><br/>
<% end %>
Try something like this.
<%= #course.name %>
<% #quiz.notes.select { |n| n.title == #course.name }.each do |note| %>
<%= link_to note.title, quiz_note_path(#quiz, note) %><br/>
<% end %>
Enumerable.select evaluates the block and returns only the elements for which it was true.