Nested_form has_one association - ruby-on-rails

I have 2 models dog and litter_field:
class Dog < ActiveRecord::Base
belongs_to :user
has_one :litter_field
accepts_nested_attributes_for :litter_field
attr_accessible :litter_field_attributes
end
class LitterField < ActiveRecord::Base
belongs_to :dog
attr_accessible :breed_type
end
In my controller I have:
class DogsController < ApplicationController
def edit
#dog = Dog.find(params[:id])
#dog.build_litter_field
end
And in my view I have:
<%= simple_form_for #dog do |f| %>
<%= f.fields_for :litter_field do |l| %>
<div>
<%= l.label :breed_type %>
<%= l.input_field :breed_type %>
</div>
<%= f.button :submit, "Save" %>
<% end %>
I've looked at the documentation and from what I can tell this should work, however this page is not on the main edit page which I'm assuming is where the problem lies. Should I be adding what's in the edit action to a new action which displays the litter_field edit form?
EDIT:
What I am trying to do is split the edit form into separate pages, I've done this by adding additional actions that render extra pages so a user would go to dogs/settings/litter for example to see the litter_field nested form. I've tried adding #dog.build_litter_field to the litter action which displays the fields but when I try and save the form I am getting the error:
Failed to remove the existing associated litter_field. The record failed to save when after its foreign key was set to nil.
EDIT 2:
Fixed the above with adding:
has_one :litter_field, :dependent => :destroy
accepts_nested_attributes_for :litter_field, update_only: true
To dog.rb, the only problem I have now is it won't display the saved value on edit.

If you call #dog.build_litter_field in the edit action, it will build a new LitterField overtop of whatever had been saved previously. I would suggest trying something like this to see if it solves the problem you are currently seeing:
def edit
#dog = Dog.find(params[:id])
#dog.build_litter_field if #dog.litter_field.nil?
end
It can also help to checkout the debugger gem. You can use that to step through controller actions and see what the objects look like after each statement.

Related

Fetch id of selected option in dropdown in controller

I have a model named 'Assessment':
class Assessment < ApplicationRecord
has_many :assessment_students
has_many :students, through: :assessment_students
end
Join table is:
class AssessmentStudent < ApplicationRecord
belongs_to :student
belongs_to :assessment
end
There is another model:
class Classroom < ApplicationRecord
has_many :classroom_students
has_many :students, through: :classroom_students
has_many :assessments
end
In show,html.erb of classrooms, I have a dropdown which shows all assessments (generated from assessment table).
Code is:
<%= collection_select(:assessment :assessment_id, Assessment.all, :id, :assessment_name , :prompt => true) %>
Requirement of the project is: Based on the assessment chosen by the user in the show.html.erb page, we have to show all students details like name etc assigned to that particular assessment. I have stored this data in join table 'AssessmentStudent '. However, I am not sure how to pass id from the above collection_select to classroom controller. I have below code:
show.html.erb:
<%= collection_select(:assessment :assessment_id, Assessment.all, :id, :assessment_name , :prompt => true) %>
<div id="divResult">
<% #assessmentstudents1.each do |t| %>
<% t.assessment_students.each do |record| %>
<%= record.student_id %>
<% end %>
<% end %>
</div>
classroom controller:
def show
#assessmentstudents1 = Assessment.find(params[:assessment][:assessment_id]).preload(:assessment_students)
end
def classroom_params
params.require(:classroom).permit(:classroom_name, :classroom_year, :customer_id, :classroom_student, :student_ids => [])
params.require(:assessment).permit(:assessment_id)
end
I would first recommend to make a change to the controller structure of your application. Because the responsibility of the show action of your ClassroomsController should be to display the details of the classroom. When you want to show the details of an Assessment, that should be handled by an AssessmentsController.
First of all, I'm gonna assume that your Assessment model has a belongs_to :classroom association. Then I would suggest creating the following structure.
config/routes.rb
resources :classrooms
resources :assessments
app/views/classrooms/show.html.erb
<% #classroom.assessments.each do |assessment| %>
<%= link_to assessment_name, assessment_path(assessment) %>
<% end %>
app/controllers/assessments_controller.rb
class AssessmentsController < ApplicationController
def show
#assessment = Assessment.find(:id)
end
end
app/views/assessments/show.html.erb
<h1>Students for <%= #assessment.assessment_name %></h1>
<% #assessment.students.each do |student| %>
<p><%= student.student_name %></p>
<% end %>
<h2>In classroom:</h2>
<p><%= #assessment.classroom.classroom_name %></p>
So to explain what is happening here, we have configured the routes to allow the server to respond to the url /assessments/:id which will lead to the AssessmentsController#show action being called.
That action is being called when the user clicks on any of the links that we have setup in the classrooms/show template. Note that I used individual links for now instead of a select dropdown, because it is easier to setup and understand how it works. And like the previous answer suggested, using a select tag requires a little bit of JavaScript to get working.
And lastly, when the assessments/show template is being rendered, it will list out all of the students related to that particular assignment. And I also included which classroom it is assigned to (if my assumption of belongs_to was correct).
On a side note, if your question tag of ruby-on-rails-3 is correct, then the usage of params.permit and params.require is invalid, because that is something that was introduced in Rails 4 (unless I'm mistaken). And in any case, you only have to use permit when database updates take place, which means the create and update actions, not index, show, etc, because it is a way of restricting which changes are allowed.
Tag select does nothing by itself. So there are two possible options.
The first is wrapping select in form tag then submitting the form will lead to request. The second is writing a handler using JavaScript which will listen to select changes.

Not able to access related objects fields

So I'm new to rails and I'm not entirely sure what I'm doing wrong. Everything I've read says that I'm doing this right.
I have a relationships between two models.
class Photo < ActiveRecord::Base
has_many :votes
belongs_to :user
end
And
class User < ActiveRecord::Base
attr_accessible :username, :email, :password, :password_confirmation, :remember_me
has_many :votes
has_many :photos
end
Here are my Controller methods
def index
#photos = Photo.order("created_at desc").to_a
end
def create
#photo = Photo.new(params[:photo])
#photo.user_id = current_user.id
if !#photo.save
#error = #photo.errors.full_messages.join('. ')
render view_for_new
return
end
end
I know the relationship works because in my view when I do this: <%= photo.user %> I get a user object back, and when I do <%= photo.user.inspect %> it shows all the expected fields with the correct keys and values.
However I want to access fields such as username, email, etc and display those on the page. How do I do this? I've tried doing <%= photo.user.email %> and some other fields that are available but it doesn't seem to be working
Alright figured this out, or at least partially.
Instead of <%= photo.user.email %> I did <%= photo.user.try(:email) %> and that brought the correct attribute back that I was looking for. It seems the association is done correctly. I don't know why <%= photo.user.email %> doesn't work, everywhere I look on line seems to use that sort of syntax.

Build form inside show action for outside model

I am trying to build a form inside the show action of a controller. Here is my setup.
Category Model
class Category < ActiveRecord::Base
# Associations
has_many :feeds
has_many :subscriptions
# Nested attributes
accepts_nested_attributes_for :subscriptions
end
Subscription Model
class Subscription < ActiveRecord::Base
# Associations
belongs_to :profile
belongs_to :category
belongs_to :feed
end
Using a Subscription namespace:
# Subscriptions
namespace :subscriptions do
resources :categories
end
Inside the show action for a category (http://URL.com/subscriptions/categories/1), I want to build the subscriptions model form and list the available feeds for that category. I want the form to submit the checked off feeds to the Subscription model.
CategoriesController
def show
#feeds = Feed.where("category_id = ?", #category)
end
Trying to build the form in the Show action of the Categories view:
<%= simple_form_for [:subscriptions, #category] do |f| %>
<%= f.association :feeds, collection: #feeds, value_method: :id, as: :check_boxes %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Right now it is rendering the appropriate information, but it is rendering as an edit form, not a create form. How do I fix this?
What else do I need to add to my routes / controller to actually get the information to save to the Subscription model?
Thanks.
first thing i am not sure where you initialize the #category object in show action and in view. if you want to render a new page than it should be map to new action of the controller and you path with will be
http://URL.com/subscriptions/categories/new
the path you are using
http://URL.com/subscriptions/categories/1
will always map to the show action according to rails convention though you can override that for you accordingly but that is not a good practice. also in new action initialize the instance by
#category = Category.new
now on submit it will automatically goes to the create action. if your #category is already persisted in the database for example
#category = Category.find(1)
now if this object goes to the simple_form_for it will send the data to update action .

Rails form_for and has_many through argument error

I'm trying to build a form_for to create a join model between two other models. I have a Book model and User model, with another called Reads that is my join. Here is how I've set up the associations:
class User < ActiveRecord::Base
has_many :reads
has_many :books, :through => :reads
end
class Book < ActiveRecord::Base
has_many :reads
has_many :users, :through => :reads
end
class Read < ActiveRecord::Base
belongs_to :book
belongs_to :user
end
I've looked at the docs for form_for and watched the railscast episode on many-to-many associations, but I can't figure out why I'm getting the error when I try to render the Book#show view where I've put the form:
First argument in form cannot contain nil or be empty
Here is my form in app/views/books/show.html.erb:
<%= form_for(#read) do |f| %>
<%= f.hidden_field :book_id, value: #book.id %>
<%= button_to 'Add to Reads', {controller: 'reads', action: 'create'}, {class: 'btn'} %>
<% end %>
I think part of the problem is that I am trying to create a 'Reads' object from the Books model, but I'm not sure what I am doing wrong. I need the 'Add to Reads' button on the Book's page so that a user can select that particular book to add to their 'reads.' I'm also adding the current_user id in the controller, rather than in the view. Here is my create action from the Reads controller if that helps...
def create
#read = Read.new(read_params)
#read.user_id = current_user.id
#read.save
if #read.save
# do this
else
# do that
end
end
And I'm using strong params...
def read_params
params.require(:read).permit(:user_id, :book_id)
end
Thanks for any help.
First argument in form cannot contain nil or be empty
This means that #read in your form is nil. Since you are in the show action of your Books controller, you have to define this variable in the books controller.
def show
#read = Read.new
...
end

has_one relationship not working on new/create

I have these models:
class User < ActiveRecord::Base
has_one :user_tms, :dependent => :destroy
accepts_nested_attributes_for :user_tms
end
class UserTms < ActiveRecord::Base
belongs_to :user
end
In the UsersController I have this:
def new
#user = User.new
#user.build_user_tms
end
And the user form looks like this:
<%= form_for(#user) do |f| %>
<%= f.collection_select(:company_id, #companies, :id, :name, :include_blank => true) %>
<%= f.fields_for(:user_tms) do |tms_form| %>
<%= tms_form.collection_select(:department, #departments, :id, :description) %>
<% end %>
<% end %>
Pretty basic stuff I think, but when submitting the form I get the error:
User tms user can't be blank
And the weird thing is that when editing an exisiting user, everything works fine. Any idea what is going wrong here? Thanks!
Not sure but it is unusual to has a class end with an "s".
What is the table name? user_tms or user_tmses. I would set the plural name in your model.
I could have missed something else if so I'll delete. It is best to have a better model name for new developers though. tms doesn't mean much to most people.
Hmm, this is really weird because I thought rails is taking care of this automatically but it seems your nested model is missing the reference to the 'nester'. Try to supply it manually.
#user.user_tms.user = #user
You have to do this in the create action ie. where the record gets saved.
What version of rails are you using?
I found out what's wrong, I had a method causing some trouble with a false return value, which interfered with the normal handling of the relations with these two models.

Resources