How to create nested model from partial Rails 6
When building an associated record over a has_one
relation, instead of
@review = entry.review.build(review_params)
you need to use the following:
@review = entry.build_review(review_params)
See the documentation for more details.
Am I suppose to implement my actions in the entries_controller?
It depends on what you're after. If you have a dedicated form for adding a new review and it is not embedded in another form for creating or updating an entry then implementing a create
action in ReviewsController
is the straightforward solution – in this case you should also not need accepts_nested_attributes_for
in Entry
.
If, however, you want to be able to create or update an entry as well as its review using the same form, then you should nest the review form in the form of the entry, keep accepts_nested_attributes_for
, and use actions in EntriesController
. The documentation should get you started there.
How to DRY a Rails 6 partial form
To create a form that routes to a nested route you pass an array:
# app/views/jobs/_form.html.erb
<%= form_with(model: [user, job]) %>
# ...
<% end %>
# app/views/jobs/new.html.erb
<%= render 'form' user: current_user, job: @job %>
# app/views/jobs/edit.html.erb
<%= render 'form' user: current_user, job: @job %>
But its kind of questionable why you nested the route in the first place as you're not using it as a nested resource at all. GET /users/:user_id/jobs
should really show only the jobs belonging to that user and POST /users/:user_id/jobs
should create a job belonging to that user and not the current user.
Use a single form_with to create and edit nested resources in Rails
You can pass an array to the form to handle both nested and "shallow" routes:
<%= form_with(model: [@series, @book], local: true) do |form| %>
<% end %>
Rails compacts the array (removes nil values) so if @series
is nil the form will fall back to book_url(@book)
or books_url
. However you need to handle setting @series
and @book
properly from the controller.
class SeriesController < ApplicationController
def show
@series = Series.find(params[:id])
@book = @series.books.new # used by the form
end
end
You could instead handle this in your views by using local variables:
# app/views/books/_form.html.erb
<%= form_with(model: model, local: true) do |form| %>
<% end %>
# app/views/books/edit.html.erb
<%= render 'form', locals: { model: [@series, @book] } %>
# app/views/series/show.html.erb
<%= render 'books/form', locals: { model: [@series, @series.book.new] } %>
You can also use the shallow: true
option in your routes to avoid nesting the member routes (show, edit, update, destroy):
resources :series do
resources :books, shallow: true
end
This will let you just do:
# app/views/books/edit.html.erb
<%= render 'form', model: @book %>
# app/views/books/_book.html.erb
<%= link_to 'Edit', edit_book_path(book) %>
Using a partial from another view while that model's routes are nested in the current view Rails 3
I was able to get this resolved by changing:
<%= form_for @personal_info, url: user_personal_info_index_path, html: { method: :post } do |f| %>
to:
<%= form_for @personal_info, url: new_user_personal_info_index_path, html: { method: :post } do |f| %>
form_with using a nested partial renders the form contents outside of the form/form elements tables, rendering content into a table row
Fixed!
My problem was that I was rendering some content into a table row <tr>
content that was not wrapped inside of a <td>
never render content into a <tr>
without wrapping that content inside of a <td>
this malformed content was breaking the form, making the contents come outside of the form as explained above
How to update @model.submodel in rails 6
I think I found the problem after @yzalavin suggestion. Somehow validations were preventing the update. I do not know the association yet.
Simply adding on: :create
allowed me o update.
validates_presence_of :entry_id, :user_id, :verified, on: :create
Render partial from another model
Very strange — if you write <%= render :partial => 'room_form' %>
than rails will assume that it is app/views/calculator/_room_form.html.erb
, but in case of <%= render :partial => 'rooms/room_form' %> it will assume that it is app/views/rooms/_room_form.html.erb
Watch your log — there you will see which partials were rendered
NoMethodError within nested model form
Having implemented the functionality you seek, I'll give some ideas:
Accepts Nested Attributes For
As you already know, you can pass attributes from a parent to nested model by using the accepts_nested_attributes_for
function
Although relatively simple, it's got a learning curve. So I'll explain how to use it here:
#app/models/plan.rb
Class Plan < ActiveRecord::Base
has_many :exercises
accepts_nested_attributes_for :exercises, allow_destroy: true
end
This gives the plan
model the "command" to send through any extra data, if presented correctly
To send the data correctly (in Rails 4), there are several important steps:
1. Build the ActiveRecord Object
2. Use `f.fields_for` To Display The Nested Fields
3. Handle The Data With Strong Params
Build The ActiveRecord Object
#app/controllers/plans_controller.rb
def new
@plan = Plan.new
@plan.exericses.build
end
Use f.fields_for To Display Nested Fields
#app/views/plans/new.html.erb
<%= form_for @plans do |f| %>
<%= f.fields_for :exercises do |builder| %>
<%= builder.text_field :example_field %>
<% end %>
<% end %>
Handle The Data With Strong Params
#app/controllers/plans_controller.rb
def create
@plan = Plan.new(plans_params)
@plan.save
end
private
def plans_params
params.require(:plan).permit(:fields, exerices_attributes: [:extra_fields])
end
This should pass the required data to your nested model. Without this, you'll not pass the data, and your nested forms won't work at all
Appending Extra Fields
Appending extra fields is the tricky part
The problem is that generating new f.fields_for
objects on the fly is only possible within a form
object (which only exists in an instance)
Ryan Bates gets around this by sending the current form
object through to a helper, but this causes a problem because the helper then appends the entire source code for the new field into a links' on click
event (inefficient)
We found this tutorial more apt
It works like this:
- Create 2 partials:
f.fields_for
&form
partial (for ajax) - Create new route (ajax endpoint)
- Create new controller action (to add extra field)
- Create JS to add extra field
Create 2 Partials
#app/views/plans/add_exercise.html.erb
<%= form_for @plan, :url => plans_path, :authenticity_token => false do |f| %>
<%= render :partial => "plans/exercises_fields", locals: {f: f, child_index: Time.now.to_i} %>
<% end %>
#app/views/plans/_exercise_fields.html.erb
<%= f.fields_for :exercises, :child_index => child_index do |builder| %>
<%= builder.text_field :example %>
<% end %>
Create New Route
#config/routes.rb
resources :plans do
collection do
get :add_exercise
end
end
Create Controller Action
#app/controllers/plans_controller.rb
def add_exercise
@plan = Plan.new
@plan.exercises.build
render "add_exericse", :layout => false
end
Create JS to Add The Extra Field
#app/assets/javascripts/plans.js.coffee
$ ->
$(document).on "click", "#add_exercise", (e) ->
e.preventDefault();
#Ajax
$.ajax
url: '/messages/add_exercise'
success: (data) ->
el_to_add = $(data).html()
$('#exercises').append(el_to_add)
error: (data) ->
alert "Sorry, There Was An Error!"
Apologies for the mammoth post, but it should work & help show you more info
Related Topics
Selenium Webdriver Take Screenshot of Viewport Only
Loaderror - Cannot Open Shared Object File - File Is Present, But It Says No Such File
Why Won't Ternary Operator Work with Redirect
Tilt (Kramdown) Preventing Erb Processing When Rendering Markdown
Perfect Way to Write a Gsub for a Regex Match
How to Access Ruby Method Inside Module and Inside a Class from Another .Rb File
How to Merge Two Equally Sized Arrays into One Array with Sub-Arrays of Merged Values
"Private Method 'Gets' Called for "Parker":String
Split String into Equal Slices/Chunks
How to Replace Text in a Ruby String
Connection Refused Using Sunspot and Solr in Rails
In Ruby, How to Know in the Console What a Method Does
How to Sign Out in a Rails App, Using Devise Gem, No Route Matches /Users/Sign_Out
Instantiate Capybara Browser and Set a Proxy
Ruby Selenium Web Drive: How to Find Specific Element by Xpath Div Id and CSS Class