Adding a form to a view gives me a routing issue - ruby-on-rails-3

I've 3 controllers/models in my rails app:
peppers
events
links
peppers model
has_many :events
events model
belongs_to :pepper
has_many :links
links model
belongs_to :event
route file
Peps::Application.routes.draw do
resources :events do
resources :links
end
resources :peppers do
resources :events
end
resources :links
resources :events
resources :peppers
end
view
<p id="notice"><%= notice %></p>
<%= form_for([#pepper, #pepper.events.build]) do |f| %>
<p>Titolo : <%= f.text_field :title %></p>
<p>Note: <%= f.text_area :note %></p>
<p><%= f.submit "Aggiungi evento" %></p>
<% end %>
<p>
<b>Title:</b>
<%= #pepper.title %>
</p>
<p>
<b>Note:</b>
<%= #pepper.note %>
</p>
<hr>
<% for event in #events %>
<h3><%= event.title %></h3>
<p><%= event.note %></p>
<ul>
<% for link in event.links %>
<li><%= link.url %></li>
<% end %>
</ul>
<%= link_to 'Cancella evento', link, confirm: 'Are you sure?', method: :delete %>
<% end %>
<%= link_to 'Edit', edit_pepper_path(#pepper) %> |
<%= link_to 'Back', peppers_path %>
This view work very well and no errors appears.
But if I add this form after the <ul> element
<%= form_for([event, event.links.build]) do |f| %>
<p><%= f.text_field :url %></p>
<p><%= f.submit "Aggiungi link" %></p>
<% end %>
I get this error
No route matches {:controller=>"links", :format=>nil, :event_id=>#<Event id: nil, title: nil, note: nil, created_at: nil, updated_at: nil, pepper_id: 4>}
What this error is for?

Without seeing your controller code I can't be sure of this, but I suspect the issue is that #events is a Rails relation instead of a proper array. In your controller, if you have something like:
#events = #pepper.events
you will want to change that to:
#events = #pepper.events.all
to force #events to resolve to a concrete array. Otherwise, iterating over #events will include the empty event you built for your first form:
<%= form_for([#pepper, #pepper.events.build]) do |f| %>
If this does not solve your issue, please post the relevant controller code for this view.

Related

accepts_nested_attributes_for only display one record when used with has_many

My models
class Game < ApplicationRecord
has_many :rounds
accepts_nested_attributes_for :rounds
end
class Round < ApplicationRecord
belongs_to :game
end
controller
def new
#game = Game.new
3.times { #game.rounds.build }
end
view
<%= form_with scope: :game, url: games_path, local: true do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :game_date %><br>
<%= form.date_field :game_date %>
</p>
<ul>
<%= form.fields_for :rounds do |builder| %>
<li>
<%= builder.label :title %>
<%= builder.text_field :title %>
<%= builder.label :order %>
<%= builder.text_field :order %>
</li>
<% end %>
</ul>
<p>
<%= form.submit %>
</p>
<% end %>
The above code only generates one "round" of record when new is building 3 records.
I am on rails 5.2.1
It is because you have a different object (formbuilder) when using form.
<%= form_with model: #game, local: true do |form| %>
Or
<%= form_with scope: #game, url: games_path, local: true do |form| %>
instead of
<%= form_with scope: :game, url: games_path, local: true do |form| %>
which produces the desire result. Have a look at this blog for better understanding.
It turns out you have to use form_for instead of the new form_with.

Creating nested form in Rails 3.1

I am trying to render a partial which I have set up as the following. I have am also trying to create a nested form whereby I have included accepts_nested_attributes_for :user in my hospital_bookings model. I seem to be getting the following error:
NameError in Rota_days#index
Showing
C:/Users/home/Desktop/Portal/app/views/rota_days/index.html.erb
where line #31 raised:
undefined local variable or method `hospital_booking' for
which is pointing to the following line <%= render :partial => "booking_dialog", :locals => { :booking => hospital_booking.new } %> of my index.html.erb as shown below. I thought it was something to do with my pluralization. By changing hospital_bookings.new to hospital_booking.new but this did not work
_booking_dialog.html.erb
<%= form_for booking do |f| %>
<%= f.fields_for :user do |f| %>
<br/>
<%= f.label :name %>
<br/>
<%= f.text_field :name %>
<%= f.hidden_field :hospital_id %>
<%= f.hidden_field :id unless booking.new_record? %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
hospital_booking.new is nonsensical: you have no local variable named hospital_booking. If you want a new instance of the HospitalBooking model, then you want HospitalBooking.new.
So:
<%= render :partial => "booking_dialog", :locals => { :booking => HospitalBooking.new } %>
Update (from the comments)
In the booking_dialog form partial, you need to put the name attribute on the associated user record inside a fields_for block, to distinguish it from the fields for the parent (booking):
<%= form_for booking do |f| %>
<%= fields_for :user do |user_fields| %>
<%= user_fields.label :name %>
<%= user_fields.text_field :name %>
<% end %>
<%= f.hidden_field :hospital_id %>
<%= f.hidden_field :id unless booking.new_record? %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
p.s. it seems very strange that you have a hidden field for the :id in here. You shouldn't need that.

How to flash error for particular validation

I am trying to flash messages in a form when they do not meet the validation requirements but can't work out how to achieve this.
I have the following setup:
models/item.rb
class Item < ActiveRecord::Base
attr_accessible :condition, :day, :description, :subtitle, :title
validates :user_id, presence: true
validates :title, presence: true
validates :description, presence: true, length: { minimum: 20 }
belongs_to :user
end
controllers/items_controller.rb
class ItemsController < ApplicationController
before_filter :authenticate_user!
def new
#item = Item.new
end
def show
#item = Item.find(params[:id])
end
def create
#item = current_user.items.build(params[:item])
if #item.save
flash[:success] = "Your item has been saved"
redirect_to root_path
else
render 'new'
end
end
def destroy
#item.destroy
redirect_back_or root_path
end
end
and finally views/items/new.html.erb
<h1>Items Base</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#item) do |f| %>
<%= f.label :title, "Title" %>
<%= f.text_field :title %>
<%= f.label :subtitle, "Subtitle" %>
<%= f.text_field :subtitle %>
<%= f.label :condition, "Condition" %>
<%= f.number_field :condition %>
<%= f.label :description, "Description" %>
<%= f.text_field :description %>
<%= f.label :day, "Day" %>
<%= f.text_field :day %>
<%= f.submit "List", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
Essentially I would like to be able to flash the message "Description too short!" when the user leaves it blank or below 20 characters, or flash the message "Title required" if it is left blank. Any thoughts on how best to achieve this. Also if anyone has any good resources on working with the flash it would be much appreciated. Thanks.
Here is how I do it:
Here is the form:
<%= form_for(#client) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :company_name %>
<%= f.text_field :company_name %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
And here is my error_messages partial:
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

Can't trigger this controller action in a view (it isn't a default Rails RESTful action)

I have a controller called votes_controller.rb. In that file there is the following action:
class VotesController < ApplicationController
def vote_up
#post = Post.find(params[:post_id])
vote_attr = params[:vote].merge :user_id => current_user.id, :polarity => 1
#vote = #post.votes.create(vote_attr)
end
(etc...)
I want to trigger the vote_up action in a view:
views/posts/show.html.erb::
<%= link_to "Vote Up", ??? %>
Here is the whole file just in case:
<h2>posts show</h2>
<span>Title: <%= #post.title %></span><br />
<span>Content: <%= #post.content %></span><br />
<span>User: <%= #post.user.username %></span><br />
<%= link_to "Vote Up", ??? %>
<h2>Comments</h2>
<% #post.comments.each do |comment| %>
<p>
<b>Comment:</b>
<%= comment.content %>
</p>
<p>
<b>Commenter</b>
<%= link_to comment.user.username, comment.user %>
</p>
<% end %>
<h2>Add a comment:</h2>
<%= form_for([#post, #post.comments.build]) do |f| %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<% if current_user.id == #post.user_id %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<% end %>
<%= link_to 'Back', posts_path %>
I have no idea what to type in the ??? part (I would also like to make it work as :remote. My intention is to trigger the action without refreshing the page).
Do I have to add something in the routes.rb?
Any suggestions?
You have to define a route in routes.rb. Use a named route to be easy to use in the view. Something like:
get 'votes/:id/vote_up' => 'votes#vote_up', as: 'vote_up'
And so can now use in the view
<%= link_to "Vote Up", vote_up_path(#post) %>
and in the controller
def vote_up
#post = Post.find(params[:id])
...
end
See Rails routing

options within nested form

Trying to make a nested form, which is working fine so far, except i need to put some dropdowns for the user to choose, as well as maybe make a couple of validations, however it seems nothing gets out of the form properly and keep getting errors no matter what I try.
three models.
--configuration
has_many :configoptions
accepts_nested_attributes_for :configoptions
--configoption
belongs_to :configuration
has_many :items
and item
belongs_to :configoption
scope :sorted, order('items.position ASC')
Now, so far I'm creating a nested form, looping through the configoptions, but for each option is possible there's more than one item. So I want to make a drop-down for those options where this is the case.
In my view i have:
<p>
<th>Elements</th>
<th>Quantity</th>
</p>
<%= form_for #config, :url => {:action => 'show', :id => #config.id} do |f| %>
<%= f.fields_for :configoptions do |fp| %>
<p>
<% if :items.count > 1 %>
<%= fp.text_field :name %>
<% else %>
<% fp.select(:items, :name)%>
<% end %>
<%= fp.text_field :quantity %>
</p>
<% end %>
<%= f.submit %>
<% end %>
I get an error obviously telling me that it can't count the :items.
How do you think I can make this work?
Thanks!
<%= form_for #config, :url => {:action => 'show', :id => #config.id} do |f| %>
<%= f.fields_for :configoptions do |fp| %>
<%= fp.text_field :id %>
<%= fp.text_field :name %>
<%= fp.text_field :quantity %>
<% end %>
<%= f.submit %>
<% end %>
OK, I think I figured it out, at least it seems to be doing what I want now.
I modified the view to pass the instance of the configoption into the nested form itself to be able to create the drop downs.
<% for configoption in #config.configoptions %>
<%= f.fields_for :configoptions, configoption do |fp| %>
<p>
<% if configoption.items.count > 1 %>
<%= fp.select (:name, options_from_collection_for_select(configoption.items.sorted, 'name', 'name'))%>
<% else %>