Rails two connected models in one view - ruby-on-rails

Suppose we have the Lyric model:
class Lyric < ActiveRecord::Base
belongs_to :song
end
and the Song model:
class Song < ActiveRecord::Base
has_many :artist, :through => :artistsong
belongs_to :album
has_one :lyric
accepts_nested_attributes_for :lyric #is this needed?
end
The migration script for songs:
class CreateSongs < ActiveRecord::Migration
def change
create_table :songs do |t|
t.integer :track
t.string :name
t.references :album
t.timestamps
end
add_index :songs, :album_id
end
end
The migration script for lyrics:
class CreateLyrics < ActiveRecord::Migration
def change
create_table :lyrics do |t|
t.text :lyric
t.references :song
t.timestamps
end
add_index :lyrics, :song_id
end
end
And suppose I have a song called "song 1" and with its lyrics attached in the database.
so the song table:
|id|name |
-------------------------
|1 |song1 |
and the lyrics table:
|id|song_id|lyrics |
---------------------------------
|1 |1 |blahblah |
in the song_controller.rb's edit method:
# GET /songs/1/edit
def edit
#song = Song.find(params[:id], :include=>:lyric)
end
This is the view to edit the song: (after the fix suggested by Matteo)
<%= form_for(#song) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<% f.fields_for :song_text do |child_form| %>
<%= child_form.label :lyrics %><br />
<%= child_form.text_field :lyrics %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
if I do:
<%= debug(#song.lyric) %>
I can see the contents of the lyrics:
--- !ruby/object:Lyric
attributes:
id: 1
song_text: hid
song_id: 2
created_at: 2012-02-07 00:59:14.000000000Z
updated_at: 2012-02-07 07:21:57.000000000Z
But in the view the textarea for lyrics disappeared completely...
I want to be able to edit the song's name and the lyrics in the same form, is this possible?
Thanks

Try to change the :lyric in the fields_for because the name of the field in the table lyrics is not lyric but lyrics
<% f.fields_for :lyric do |child_form| %>
<%= child_form.label :lyrics %><br />
<%= child_form.text_field :lyrics %>
<% end %>

<%= child_form.label :lyric %><br />
<%= child_form.text_field :lyric %>
Should both be :lyrics plural, not :lyric

Related

question id is not updating according to the user_choice option

Hope you all are well
I am creating a quiz application in which i have 3 models one question.rb, user.rb and result.rb
Question.rb
class Question < ApplicationRecord
validates :question, presence: true
validates :option1, presence: true
validates :option2, presence: true
validates :option3, presence: true
validates :option4, presence: true
validates :answer, presence: true
end
migrated file
class CreateQuestions < ActiveRecord::Migration[6.1]
def change
create_table :questions do |t|
t.text :question
t.text :option1
t.text :option2
t.text :option3
t.text :option4
t.text :answer
t.timestamps
end
end
end
result.rb
class CreateResults < ActiveRecord::Migration[6.1]
def change
create_table :results do |t|
t.text :user_choice
t.timestamps
end
end
end
Also question_id and User_id are the Foreign keys in this table.
result controller
class ResultController < ApplicationController
def create
#result=Result.create(user_choice: params[:user_choice],
question_id: params[:question_id],
user_id: current_user.id)
end
end
and finally
view/question/index
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body ">
<!-- Nested Row within Card Body -->
<div class="row py-5">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4 ">Multiple-Choice Questions</h1>
</div>
<%= form_with model: #result ,url: result_path do |f| %>
<% #questions.each do |question| %>
<div>
<%= f.hidden_field :question_id, value: question.id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<p><%= question.question %></p>
<% choices = [question.option1, question.option2, question.option3, question.option4] %>
<% choices.each do |c| %>
<div>
<%= f.radio_button :"user_choice[#{question.id}]", c %>
<%= f.label :user_choice, c %>
</div>
<% end %>
</div>
<% end %>
<div class="sub"> <%= f.submit "Submit", class:"btn btn-primary" %></div>
<% end %>
<div class="para1"><%= link_to 'New Question', new_question_path,class:"btn btn-primary btn-user" %>
</div>
</div>
</div>
</div>
</div>
</div>
Now everything is working perfectly the user choice is saving and user id is also saving current_user.id
Now the issue is question_id is not updating it's always show the id the last question have. In my cause it's 11. I don't know why it's not storing the id of the answered question.
Please i will be thankful if somebody help me in this.
class CreateResults < ActiveRecord::Migration[6.1]
def change
create_table :results do |t|
t.text :user_choice
t.timestamps
end
end
end
There is no question_id attribute for a result record.
If you meant to connect Question to Result you need to define the relationships on the models:
class Question < ApplicationRecord
has_many :results
end
class Result < ApplicationRecord
belongs_to :question
belongs_to :user
end
And you'll need your foreign keys on Result:
class CreateResults < ActiveRecord::Migration[6.1]
def change
create_table :results do |t|
t.text :user_choice
t.references :question
t.references :user
t.timestamps
end
end
end
Now Result will have question_id and user_id

Rails5 - Update join table with has_many :through : using fields_for

I have a trouble to update my join table course_students.
When I create a new student, I want to select a course from dropdown list(from two courses Course1 and Course2 which already saved in course table) and update course_students. And I want my couse_students table to be something like this.
id | student_id | course_id | created_at | updated_at
----+------------+-----------+----------------------------+----------------------------
1 | 1 | 1 | 2017-08-23 16:41:57.228094 | 2017-08-23 16:41:57.228094
Thanks to http://railscasts.com/episodes/17-habtm-checkboxes-revised?view=asciicast, I somehow found out the following code works for radio_button_tag. But there is an error wrong number of arguments when I change radio_button_tag to select_tag.
Also, I am not sure if this is the correct way because the information seems bit old. After some google search, I often found that people use field_for in new.html.erb, so I tried but I could not update course_students table.
In the future, I would like to add other columns like teacher, date_from, class_room, and something like that in course_students table.
I would really appreciate your help.
・models
class Student < ApplicationRecord
has_many :course_students
has_many :courses, :through => :course_students
accepts_nested_attributes_for :course_students
end
class Course < ApplicationRecord
has_many :course_students
has_many :students, :through => :course_students
end
class CourseStudent < ApplicationRecord
belongs_to :student
belongs_to :course
end
・migrations
class CreateStudents < ActiveRecord::Migration[5.1]
def change
create_table :students do |t|
t.string :first_name
t.string :middle_name
t.string :last_name
t.timestamps
end
end
end
class CreateCourses < ActiveRecord::Migration[5.1]
def change
create_table :courses do |t|
t.string :name
t.timestamps
end
end
end
class CreateCourseStudents < ActiveRecord::Migration[5.1]
def change
create_table :course_students do |t|
t.integer :student_id
t.integer :course_id
t.timestamps
end
end
end
・course table
id | name | created_at | updated_at
----+--------------+----------------------------+----------------------------
1 | Course1 | 2017-08-22 20:03:46.226893 | 2017-08-22 20:03:46.226893
2 | Course2 | 2017-08-22 20:03:46.228765 | 2017-08-22 20:03:46.228765
・student.controller, strong params.
def student_params
params.require(:student).permit(:first_name, :middle_name, :last_name, course_ids: [], date_froms: [] )
end
・new.html.erb
<h1>Create new student</h1>
<%= form_for(#student) do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :middle_name %>
<%= f.text_field :middle_name %>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
<%= Course.all.each do |course| %>
<%= radio_button_tag "student[course_ids][]", course.id, #student.course_ids.include?(course.id), id: dom_id(course)%>
<%= label_tag dom_id(course), course.name %>
<% end %>
<%= f.submit "Create new student", class: "btn btn-primary" %>
<% end %>
Use nested_form_for instead of form_for and for course_students use field_for that nested form helper provide. https://github.com/ryanb/nested_form
<h1>Create new student</h1>
<%= nested_form_for(#student) do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :middle_name %>
<%= f.text_field :middle_name %>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
<%= f.fields_for :course_students do |ff| %>
<%= ff.hidden_field :student_id, value: #student.id %>
<%= ff.collection_select :course_id, Course.all, :id, :name %>
<% end %>
<%= f.submit "Create new student", class: "btn btn-primary" %>
<% end %>
you needs to permit course_students params in controller like this:
def student_params
params.require(:student).permit(:first_name, :middle_name, :last_name, course_students_attributes: [ :course_id, :student_id] )
end
Found out that the following code worked!
students_controller
def new
#student = Student.new
#student.course_students.build
end
private
def student_params
params.require(:student).permit(:first_name, :middle_name, :last_name, course_students_attributes: [ :course_id, :student_id] )
end
new.html.erb
<%= f.fields_for :course_students do |ff| %>
<%= ff.hidden_field :student_id, value: #student.id %>
<%= ff.collection_select :course_id, Course.all, :id, :name %>
<% end %>
Thanks!

Creating Rails objects using same form

I am building an application to manage debts and am trying to create three objects using the same form.
The models are;
Debt (the amount owed)
class Debt < ActiveRecord::Base
belongs_to :user
belongs_to :creditor
belongs_to :debtor
accepts_nested_attributes_for :debtor, :creditor
end
Debtor (The person who owes)
class Debtor < ActiveRecord::Base
belongs_to :user
has_many :debts
end
Creditor (The person who is owed)
class Creditor < ActiveRecord::Base
belongs_to :user
has_many :debts
end
I am using the new debt form and would like to show fields for debtor and creditor. So when a new debt is created, so is the associated debtor and creditor.
I have viewed the documentation however, cannot get the fields for debtor or creditor to display on the form.
This is the form
<%= simple_form_for(#debt) do |f| %>
<%= f.error_notification %>
<!-- Debt fields -->
<div class="form-inputs">
<%= f.association :user %>
<%= f.input :amount %>
<%= f.input :commission %>
<%= f.input :invoice_issued %>
<%= f.input :invoice_date %>
<%= f.input :status %>
<%= f.input :details %>
</div>
<!-- Debtor Fields -->
<ul>
<%= f.fields_for :debtor do |debtor_form| %>
<li>
<%= debtor_form.association :user %>
<%= debtor_form.input :business_name %>
<%= debtor_form.input :abn %>
<%= debtor_form.input :first_name %>
<%= debtor_form.input :last_name %>
<%= debtor_form.input :email %>
<%= debtor_form.input :mobile_number %>
<%= debtor_form.input :phone_number %>
</li>
<% end %>
</ul>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Any help is appreciated.
EDIT
create_table "debts", force: :cascade do |t|
t.integer "user_id"
t.float "amount"
t.float "commission"
t.boolean "invoice_issued"
t.date "invoice_date"
t.string "status"
t.text "details"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
You need to build your debt's debtor or creditor in your controller:
#controller
def new
#debt = Debt.new
#debt.build_debtor
#bebt.build_creditor
end

nested attributes not displaying form correctly

I have a form from user
<%= form_for(#user) do |f| %>
<%= f.fields_for :businesses do |field| %>
<div class="field">
<%= field.label :address %>
<%= field.text_field :address %>
</div>
<div class="field">
<%= field.label :city %>
<%= field.text_field :city %>
</div>
<% end %>
<% end %>
It does not display my fields, but when i change businesses to business, then it shows, or if I remove the f from f.fields_for. But I don't think it properly saves into database.
my user model
class User < ActiveRecord::Base
has_many :businesses
accepts_nested_attributes_for :businesses
en
my business model
class Business < ActiveRecord::Base
attr_accessible :user_id, :address, :city
belongs_to :user
end
my bussiness migration
class CreateBusinesses < ActiveRecord::Migration
def change
create_table :businesses do |t|
t.integer :user_id
t.string :address
t.string :city
t.timestamps
end
end
end
Any suggestions as to what I'm doing wrong?
Thanks
You should build a business before it can display a form for it:
#user.businesses.build
Use that before using fields_for
Also check out this great gem for managing nested forms:
https://github.com/ryanb/nested_form

How are parameters passed for nested attributes in Rails?

I have two models, Ingredients and Foods:
class Food < ActiveRecord::Base
belongs_to :user
has_many :ingredients
accepts_nested_attributes_for :ingredients
attr_accessible :name, :price
end
class Ingredient < ActiveRecord::Base
belongs_to :user
belongs_to :food
attr_accessible :ingredient_name, :quantity_used
end
The schemas for the two models are as follows:
create_table "foods", :force => true do |t|
t.string "name"
t.integer "user_id"
t.float "price"
t.string "ingredient_name"
end
create_table "ingredients", :force => true do |t|
t.string "ingredient_name"
t.integer "user_id"
t.integer "food_id"
t.integer "quantity_used"
end
I'm creating a form for Food which also creates/updates the Ingredient table as well. I have the form working, and the submit button updates the correct attributes, but I have other attributes in each table that I want to update as well. For example, in the Food Controller, I want to do something like ingredient.user_id = current_user.id. I understand I can access things through params[:food], but how do I access individual fields which aren't being updates by the form?
Right now, my form is:
<%= form_for(#food) do |f| %>
<div class="field">
<%= f.label :Name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :price %><br />
<%= f.number_field :price %>
</div>
<div>
<%= f.fields_for :ingredients do |builder| %>
<%= builder.label "Ingredient Used:" %>
<%= builder.text_field :ingredient_name %><br />
<%= builder.label "Quantity Used:" %>
<%= builder.text_field :quantity_used %><br />
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
How do I access this specific Food's ingredients in the Food#create action?
Thanks!
You might need to add :ingredients_attributes to attr_accessible in your Food model.
You can mess about with the params hash in the controller by iterating over the :ingredients_attributes or you can use assign_attributes.

Resources