This is the thing
I have a table/class called Offer
And referenced table/class called OfferDay (because an Offer is available on x days of the week)
It's just a really simple question.
Is there a Ruby on Rails convention for editing such a thing?
My Offer admin form should have 7 checkboxes, prefilled with OfferDays for this instance (or not)
Yes of course, i can loop days of the week in my .erb and check the child collection (days) of the instance, but what about auto binding to instances on postbacK? - it seems the sort of legwork we've all seen before and should have a convention.
Yes I've googled... found sort of it, but not quite... any specific to this one?
I'd handle it with a has_many relationship:
#app/models/offer.rb
Class Offer < ActiveRecord::Base
has_many :days, -> { select(:day_id) }, class_name: "OfferDay", foreign_key: "offer_id"
accepts_nested_attributes_for :days
end
Class OfferDay < ActiveRecord::Base
belongs_to :offer
end
offer_days
id | offer_id | day_id #-> put indexes on day_id & offer_id
You'll be able to call #offer.days to reveal the days on which your offer is running. It will of course return a number, which you'll then translate into a day using the Date class or similar
Editing
This will allow you to assign any number of days to each offer (and each of the days being unique). I'd update like this:
#app/controllers/offers_controller.rb
def new
#offer = Offer.new
#offer.days.build
end
def create
#offer = Offer.new(offer_params)
#offer.save
end
private
def offer_params
params.require(:offer).permit(:offer, :attributes, days_attributes: [:day_id])
end
#app/views/offers/new.html.erb
<%= form_for #offer do |f| %>
<%= f.text_field :offer %>
<%= f.text_field :attributes %>
<%= f.fields_for :days do |builder| %>
<% 7.times do |day| %>
<%= builder.check_box :day_id, day %> #-> need label for each day
<% end %>
<% end %>
<% end %>
Related
I'm trying to associate several dinners to a meal with a has_many: through relationship when the user hits "save". My question is not with the mechanics of has_many: through. I know how to set that up and I have it working in the Rails console, but I just don't know how to set up the view to associate several records at once.
I have models set up like this:
class Dinner < ApplicationRecord
has_one :user
has_many :meals
has_many :meal_plans, through: :meals
end
class MealPlan < ApplicationRecord
belongs_to :user
has_many :meals
has_many :dinners, through: :meals
end
class Meal < ApplicationRecord
belongs_to :dinner
belongs_to :meal_plan
end
With a meal plan controller:
def create
#meal_plan = current_user.meal_plans.build(meal_plan_params)
respond_to do |format|
if #meal_plan.save
format.html { redirect_to root_path, notice: 'Dinner was successfully created.' }
end
end
end
private
def meal_plan_params
params.require(:meal_plan).permit(dinners: [])
end
My question is about the view, in the new view, I create a #meal_plan and I want to pass several different dinners into the meal plan. Below the value: #dinners is just 7 random dinners pulled from the Dinners table.
<%= form_with model: #meal_plan do |f| %>
<%= f.hidden_field(:dinners, value: #dinners)%>
<%= f.submit 'Save'%>
<% end %>
Again, I've gotten this to work by running something like `usr.meal_plans.create(dinners: [d1, d2])`` in the Rails console but I don't
You can use the form option helpers to generate selects or checkboxes:
<%= form_with model: #meal_plan do |f| %>
<%= f.collection_select :dinner_ids, Dinner.all, :id, :name, multiple: true %>
<%= f.collection_checkboxes :dinner_ids, Dinner.all, :id, :name %>
<%= f.submit 'Save'%>
<% end %>
_ids is a special setter / getter generated by ActiveRecord for has many assocations. You pass an array of ids and AR will take care of inserting/removing the join table rows (meals).
You also need to change the name in your params whitelist:
def meal_plan_params
params.require(:meal_plan).permit(dinner_ids: [])
end
If you want to to pass an array through hidden inputs you can do it like so:
<% #dinners.each do |dinner| >
<%= hidden_field_tag "meal_plans[dinner_ids][]", dinner.id %>
<% end %>
See Pass arrays & objects via querystring the Rack/Rails way for an explaination of how this works.
So I have four models
class User
has_many :user_rows
end
class Assignment
has_many :rows
end
class Row
belongs_to :assignment
has_many :user_rows
end
class UserRow
belongs_to :user
belongs_to :row
end
On the assignment show view I want to loop through the rows and for each row have a user_row to capture user input.
My question is how to intialize the user rows. Would it be best to do this?
class AssignmentController
def show
#assignment = Assignment.include(:rows).find(params[:id])
end
end
Then in the view just use first_or_create
<%= #assignment.rows.each do |row| %>
<%= row.data %>
<%= form_for UserRow.where(row_id: row.id, user_id: current_user.id).first_or_create, remote: true do |f| %>
<%= form_fields %>
<% end %>
<% end %>
As you can see the objects need to be iterated over in the view.
Which I don't like particularly because it's initializing an object in the view. Or is it best to create all the user_rows for each row when a user signs up to the site and if a new row is created create a user_row for all users?
Or is there a better solution I've missed?
I guess, fields_for and accepts_nested_attributes_for might help you. You might check these documents.
fields_for (ActionView::Helpers::FormBuilder) - APIdock
accepts_nested_attributes_for (ActiveRecord::NestedAttributes::ClassMethods) - APIdock
I've been hacking around with Rails 3.2.11 for a while, and am trying to do this the 'right' way.
I have three models (Reflection, Skill, Utilization) that relate to each other through has_many: through:
Utilization.rb
class Utilization < ActiveRecord::Base
attr_accessible :reflection, :skill, :used_skill #used_skill is a boolean
belongs_to :reflection
belongs_to :skill
end
Reflection.rb
class Reflection < ActiveRecord::Base
## attributes here ##
has_many :utilizations
has_many :skills, through: :utilizations
accepts_nested_attributes_for :utilizations
accepts_nested_attributes_for :skills
end
Skill.rb
class Skill < ActiveRecord::Base
## attributes here ##
has_many :utilizations
has_many :reflections, through: :utilizations
end
Within the app, skills are already defined. The user action I am trying to support is:
User gets form for new Reflection.
User sees a list of Skills and checks off which ones they have used (Utilization).
User posts to create new Reflection and create the associated Utilization objects.
Here is the new method reflection_controller.rb:
class ReflectionsController < ApplicationController
def new
#reflection = Reflection.new
Skill.all.each do |skill|
#reflection.utilizations.build(skill_id: skill.id, used_skill: false)
end
end
end
And an abbreviated _form.html.erb for Reflections
<%= form_for(#reflection) do |f| %>
<% f.fields_for :utilizations do |builder| %>
<%= builder.label :used_skill %>
<%= builder.check_box :used_skill %>
<%= builder.fields_for :skill do |skill| %>
<%= skill.label :description %>
<%= skill.text_field :description %>
<% end %>
<% end %>
<% end %>
So the problem is that even though there are multiple Skills and I .new the Utilization objects and associate them with the #reflection, they don't show up in the form. I've played with the data structures a little bit, and I can reach the point where in ReflectionController.new #reflection.utilizations contains Utilization objects, it still won't work; when I run #reflection.utilizations.count it returns 0. It looks like the problem is that since none of the objects have an id at that time, it simply will not render out in the form. But my understanding is that one should not create objects during the new method…
Is there something obvious I'm missing? Is there a better way to do this? I've seen examples, include Ryan Bates' Railscast where people just use code like:
def new
#survey = Survey.new
3.times do
question = #survey.questions.build
4.times { question.answers.build }
end
end
and supposedly this works fine.
I really appreciate the help. Trying to figure this out has been driving me crazy. This is my first question on SO, and I'm happy to add any clarifying data or additional code if you think it would help.
You forgot to use =:
<%#### Here ####%>
<%= f.fields_for :utilizations do |builder| %>
<%= builder.label :used_skill %>
<%= builder.check_box :used_skill %>
<%#### and here ####%>
<%= builder.fields_for :skill do |skill| %>
My app has a user model, as well as multiple other date related models/tables such as anniversaries, holidays, birthdays, and and "other dates" custom model.
I have a user dashboard view that lists them all separately as shown below. How can i display all of these lists as one (call it upcoming events or something) that is listed chronologically and shows them upcoming dates for a certain period of time.
View
*note - These are displayed in a table/list but i stripped html for clarity
<h1>Holidays</h1>
<% if #user.holidays.any? %>
<% #user.holidays.each do |hld| %>
<%= hld.name %>
<%= hld.date %>
<% end %>
<h1>Friends Birthdays</h1>
<% if #user.friends.any? %>
<% #user.friends.each do |frd| %>
<%= frd.name %>
<%= frd.dob %>
<% end %>
<h1> Anniversary </h1>
<% if #user.anniversaries.any? %>
<% #user.anniversaries.each do |ann| %>
<%= ann.spouse_name %>
<%= ann.anniversary_date %>
<% end %>
Thanks!
Models
class User < ActiveRecord::Base
has_many :friends
has_many :occasions
has_many :user_holidays
has_many :holidays, :through => :user_holidays
has_many :anniversaries
class Holiday < ActiveRecord::Base
has_many :user_holidays
has_many :users, :through => :user_holidays
end
class Friend < ActiveRecord::Base
belongs_to :user
end
class Anniversary < ActiveRecord::Base
belongs_to :user
end
Assuming you want to be efficient (you could just combine the arrays, sort them and be done with it), there is no direct way to do it through the relations. I am assuming you have an events model which has a foreign key to the user, in that case,
Events.where(:user_id => #user.id).where(<EVENT DATE FILTERS>).order("event_date DESC")
-- EDIT --
This is quite dirty, but I cant think of any other direct db way of accomplishing this.
events = #user.holidays.map{|h| [h.name, h.date, :holiday]} + \
#user.friends.map{|f| [f.name, f.dob, :birthday]} + \
#user.anniversaries.map{|a| [a.spouse_name, a.anniversary.date, :anniversary]}
events.map!{|event| {:name => event[0], :date => event[1], :event_type => event[2]}}
# You now have an array of hashes with the events name, date and type.
events.sort{|a, b| a[:date] <=> b[:date]} # sort / filter
I have the following ActiveRecord models
class User < ActiveRecord::Base
has_many :timesheets
end
class Timesheet < ActiveRecord::Base
belongs_to :user
has_many :work_days
end
class WorkDay < ActiveRecord::Base
belongs_to :timesheet
end
The WorkDay model has attributes like hours, days, comments, etc.
I can not figure out how the form would look like in rails for this.. I saw some complex forms from railscasts but still not getting it.
I am envisioning a form like below (for 7 days):
06/19 (Day1) 06/20 (Day2) 06/21 (Day3) ... 06/26 (Day 7)
textfield 1 textfield 2 textfield 3 ... textfield4
<submit>
So I have 7 textfields in this form (might have comments for each one as well).
Can someone tell me/explain me how the form_for would look for this.
You will be having something like this -
<%= form_for #timesheet do |f| %>
# Fields for #timesheet attributes.
<% f.fields_for 7.times.map{#timesheet.workd_day.new}.each do |t| %>
Hour: <%= t.text_field hour %>
Days: <%= t.text_field days %>
Comments: #one more fields for block for comments.
<% end %>
<%= f.sumit "Save" %>
<% end %>