Rails: Hidden fields not passing values - ruby-on-rails

I am trying to create a form for a site administrator to associate events with a list of previous speakers. The administrator navigates to the speaker, clicks on a button to "Add to event" and a form comes up asking for which event the speaker is attending. The speaker is supposed to be passed in as a hidden field, and the events are listed via a collection select. Unfortunately, the speaker id is not passing into the database when I submit the form.
Why is my form is not saving values from the hidden field, and how do I about fixing this? Values from the collection select are passing.
<%= form_for(#event_speaker) do |f| %>
<% if #event_speaker.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#event_speaker.errors.count, "error") %> prohibited this event_speaker from being saved:</h2>
<ul>
<% #event_speaker.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p><%= #speaker.first_name %></p>
<div class="actions">
<%= #speaker.id %>
<%= f.hidden_field(:speaker) %>
<%= hidden_field_tag('speaker_id',#speaker.id) %>
</div>
<div class="field">
<%= f.label :event %><br>
<%= f.collection_select(:event_id, #upcoming_events, :id, :name)%>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And the controller:
def new
#event_speaker = EventSpeaker.new
#speaker = Speaker.find(params[:speaker_id])
#event_speaker.speaker_id = #speaker
#Time = Time.now
#upcoming_events = Event.all
end
# GET /event_speakers/1/edit
def edit
end
# POST /event_speakers
# POST /event_speakers.json
def create
#event_speaker = EventSpeaker.new(event_speaker_params)
respond_to do |format|
if #event_speaker.save
format.html { redirect_to #event_speaker, notice: 'Event speaker was successfully created.' }
format.json { render action: 'show', status: :created, location: #event_speaker }
else
format.html { render action: 'new' }
format.json { render json: #event_speaker.errors, status: :unprocessable_entity }
end
end
end
And...
def event_speaker_params
params.require(:event_speaker).permit(:speaker_id,:event_id)
end

You should do
<%= f.hidden_field :speaker_id, :value => #speaker.id %>
This will generate your speaker_id nested inside event_speaker so your form will look like this:
<%= form_for(#event_speaker) do |f| %>
<% if #event_speaker.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#event_speaker.errors.count, "error") %> prohibited this event_speaker from being saved:</h2>
<ul>
<% #event_speaker.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p><%= #speaker.first_name %></p>
<div class="actions">
<%= f.hidden_field :speaker_id, :value => #speaker.id %>
</div>
<div class="field">
<%= f.label :event %><br>
<%= f.collection_select(:event_id, #upcoming_events, :id, :name)%>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
For details checkout hidden field in rails

Related

How to set up Edit for Remote Form in Rails?

Webpage View
So in the image button above, I have a button called "Mark Item as Done". Inside that Item table, I have a date: due_date, string: task_title, text: description, and a boolean: done.
Now I put the format.js in the todoitems_controller.rb because I figured that would be the best place to put it because I'm calling their edit link
todolist_todoitems GET /todolists/:todolist_id/todoitems(.:format) todoitems#index
POST /todolists/:todolist_id/todoitems(.:format) todoitems#create
new_todolist_todoitem GET /todolists/:todolist_id/todoitems/new(.:format) todoitems#new
edit_todolist_todoitem GET /todolists/:todolist_id/todoitems/:id/edit(.:format) todoitems#edit
todolist_todoitem GET /todolists/:todolist_id/todoitems/:id(.:format) todoitems#show
PATCH /todolists/:todolist_id/todoitems/:id(.:format) todoitems#update
PUT /todolists/:todolist_id/todoitems/:id(.:format) todoitems#update
DELETE /todolists/:todolist_id/todoitems/:id(.:format) todoitems#destroy
todolists GET /todolists(.:format) todolists#index
POST /todolists(.:format) todolists#create
new_todolist GET /todolists/new(.:format) todolists#new
edit_todolist GET /todolists/:id/edit(.:format) todolists#edit
todolist GET /todolists/:id(.:format) todolists#show
PATCH /todolists/:id(.:format) todolists#update
PUT /todolists/:id(.:format) todolists#update
DELETE /todolists/:id(.:format) todolists#destroy
root GET / todolists#index
Now, should I also be doing something to the def edit in the todoitems_controller.rb as well or just def update? And putting remote: true in the Todolists/_form.html.erb file, is it the best place to put it there or should I put it in Todoitems/_form.html.erb file? And after doing all these, what is the next step?
This is what I've managed to accomplish so far and this is my first time working with remote forms. I'm just struggling to get this started because the lectures are confusing. If there's anything else missing, I'm happy to provide more info about this! Any help would be appreciated!
todolists/show.html.erb - Look at button_to. That's the part I need help
<p>
<% #paginate_items.each do |item| %>
<div class="list">
<form class="oneLine">
<a class="notDue">
<%= item.due_date %>
</a>
<a class="linkResults">
<%= link_to "#{item.task_title}", [#todolist, item], style: "font-weight: bold;" %>
<%= button_to "Mark Item as Done", remote: true %><br/> <br/>
</a>
</form>
<% end %>
todoitems_controller.rb - I already put the render.js in the update.
def update
respond_to do |format|
if #todoitem.update(todoitem_params)
format.html { redirect_to #todolist, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #todoitem }
render.js
else
format.html { render :edit }
format.json { render json: #todoitem.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_todoitem
#todoitem = Todoitem.find(params[:id])
end
def set_todolist
#todolist = Todolist.find(params[:todolist_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def todoitem_params
params.require(:todoitem).permit(:due_date, :task_title, :description, :done, :todolist_id)
end
todolists/_form.html.erb - I already put the remote: true
<body class="page">
<%= form_for(#todolist, remote: true) do |f| %>
<% if #todolist.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#todolist.errors.count, "error") %> prohibited this todolist from being saved:</h2>
<ul>
<% #todolist.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :list_name %><br>
<%= f.text_field :list_name %>
</div>
<br/>
<div class="field">
<%= f.label :list_due_date %><br>
<%= f.text_field :list_due_date, class: 'dateSelect' %>
</div>
<br/>
<div class="actions">
<%= f.submit %>
</div>
<br/>
<% end %>
</body>
todoitems/_form.html.erb
<body class="page">
<%= form_for([#todolist, #todoitem], remote: true) do |f| %>
<% if #todoitem.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#todoitem.errors.count, "error") %> prohibited this todoitem from being saved:</h2>
<ul>
<% #todoitem.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :due_date %><br>
<%= f.text_field :due_date, class: 'dateSelect' %>
</div>
<br/>
<div class="field">
<%= f.label :task_title %><br>
<%= f.text_field :task_title %>
</div>
<br/>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description, size: "40x10" %>
</div>
<br/>
<% if !#todoitem.new_record? %>
<div class="field">
<%= f.label :done, 'Task Completed' %>
<%= f.check_box :done %>
</div>
<br/>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<br/>
<% end %>
</body>
You haven't provided all the parameters to button_to to make the form work. This helper method generates a form and you need to provide the path for the form to POST to. Have a look at the docs for the button_to helper to see what you're missing.
<%= button_to "Mark Item as Done", todolist_todoitem_path(#todolist, #todoitem), method: patch, remote_true %>
(I'm not sure what your routes are so I made it up.)
When you're updating a resource you need to provide the method (either patch or put is for updating). You might want to read up on routing as well. Initially, they can be a little confusing, but they are at the heart of an interactive rails application so understanding them is key.

Flash alert Error not displaying Rails

So I have two flash notice that should appear one if a post is saved successfully and another if there is an error creating a new post . I implemented it a while back but I just realized that the error flash isn't being displayed properly. All it displays is a red empty notice on top of the window, while the notice for a "successful save" does appear correctly.
for my controller i have :
def create
#topic = Topic.new
#topic.name = params[:topic][:name]
#topic.description = params[:topic][:description]
#topic.public = params[:topic][:public]
if #topic.save
redirect_to #topic, notice: "Topic was saved successfully."
else
flash.now[:alert] = "Error creating topic. Please try again."
render :new
end
end
new post view :
<div class="col-md-8">
<%= render partial: 'form', locals: { topic: #topic, post: #post } %>
</div>
</div>
_form.html:
<%= form_for [topic, post] do |f| %>
<% if post.errors.any? %>
<div class="alert alert-denger">
<h4><%= pluralize(post.errors.count, "error") %>.</h4>
<ul>
<% post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form_group_tag(post.errors[:title]) do %>
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control', placeholder: "Enter post title" %>
<% end %>
<%= form_group_tag(post.errors[:body]) do %>
<%= f.label :body %>
<%= f.text_area :body, rows: 8, class: 'form-control', placeholder: "Enter post body" %>
<% end %>
<div class="form-group">
<%= f.submit "Save", class: 'btn btn-success' %>
</div>
<% end %>
Please put this in application.html.erb file.
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
Try to add flash massages in your application.html.erb:
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %>">
<%= value %>
</div>
<% end %>
usually it put above <%= yield %>

How to redirect_to(:back) two times?

def update
if #note.update_attributes(note_params)
redirect_to :back, notice: "Note was updated."
else
render :edit
end
end
Is there a way to redirect back twice?
Here you go:
This is where the link for editing goes:
<p id="notice"><%= notice %></p>
<% url = "#{request.protocol}#{request.host_with_port}#{request.fullpath}" %>
<%= link_to 'Create New Page and Return Here', edit_page_path(1, :url => Base64.encode64(url) ) %>
<br>
After submit your url will be something like this:
http://localhost:3000/pages/1/edit?url=aHR0cDovL2xvY2FsaG9zdDozMDAwL2R1bW1pZXM%3D%0A
In the edit form:
I called it pages/_form.html.erb, Pass the URL as a hidden params.
<%= form_for(#page) do |f| %>
<% if #page.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#page.errors.count, "error") %> prohibited this page from being saved:</h2>
<ul>
<% #page.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :permalink %><br>
<%= f.text_field :permalink %>
</div>
<%= hidden_field_tag :url, params[:url].to_s %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In controller that you have update method, in this case pages_controller.rb, simply Base64 it back and redirect the user:
def update
redirection = nil
if params[:url].present?
redirection = Base64.decode64(params[:url].to_s)
end
if #page.update(page_params)
if redirection.present?
path = redirection
else
path = #page
end
redirect_to path, notice: 'All Done.'
else
render :edit
end
end
Now user updates the form and redirected back to the first show or index page or any page that she is coming from.
Hope this help.
PS: You might want to clean it up a bit and pass the url from the controller, and put some checks on it. So you don't define any var at the view level. In the above code I just tried to solve this issue not really a design pattern oriented :)

Errors for nested resource not displaying even if I'm using "target"?

I have the following:
routes.rb:
resources :posts do
resources :replies
end
replies_controller.rb:
class RepliesController < ApplicationController
def create
#post = Post.find(params[:post_id])
#reply = #post.replies.build(params[:reply])
#reply.user_id = current_user.id
if #reply.save
flash[:success] = "reply created!"
redirect_to post_path(#post)
else
redirect_to post_path(#post)
end
end
replies/_form.html.erb:
<%= form_for([#post, #post.replies.build]) do |f| %>
<%= render 'shared/error_messages', object: f.object, target: #reply %>
<div class="field">
<%= f.text_area :content, placeholder: "Enter reply content" %>
</div>
<%= f.submit "Reply", class: "btn btn-large btn-primary" %>
<% end %>
posts/show.html.erb:
<div class="span8">
<%= render 'replies/form' %>
</div>
shared/error_messages.html.erb:
<% 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 %>
I'm not sure why the errors messages for the replies are not displaying since I'm using target: #reply (:content and :user_id are required).
Any suggestions to fix this?
In create method's else section you have to render the post_path(#post) not redirect the post_path(#post)
try this in else part of create section
render :template => 'posts/show'
So that your current #reply object will persist for your error messages.
redirect_to post_path(#post) will redefine #reply object in show action (I assume you have defined #reply object there).
In posts/show action, build your reply object there and assign it to #reply instance object.
#reply = #post.replies.build
Now in replies/_form.html.erb:
change #post.replies.build to #reply
i.e
<%= form_for([#post, #post.replies.build]) do |f| %>
to
<%= form_for([#post, #reply]) do |f| %>
Also assign #reply to object variable while rendering 'shared/error_messages' partial,
<%= form_for([#post, #reply]) do |f| %>
<%= render :partial => 'shared/error_messages', :locals => {:object => #reply} %>
<div class="field">
<%= f.text_area :content, placeholder: "Enter reply content" %>
</div>
<%= f.submit "Reply", class: "btn btn-large btn-primary" %>
<% end %>
Also make partial for error_messages in shared folder (shared/_error_messages). In this partial paste your code which is in shared/error_messages
<% 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>

How to populate form in nested model when error occurs?

Running Rails 3.2.1.
I went through the "Getting started" guide on the Ruby on Rails site. I have set up a blog post where someone can comment on the posts.
I modified the example to show an error when I enter in comments that don't validate (no name or comment text).
(A post has multiple comments, etc.)
However, how do I have Rails put this problematic comment back in the form, instead of the page?
Here is my create method in the comments controller:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#post, :notice => 'Comment was successfully created.') }
else
format.html { render 'posts/show' }
end
end
end
Here is my show.html.erb from posts:
<%= render #post %>
<h3>Comments</h3>
<%= render #post.comments %>
<h3>Add a comment</h3>
<%= render "comments/form" %>
<p>
<% if user_signed_in? %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<% end %>
<%= link_to 'Back', posts_path %>
</p>
And here is my comment form partial:
<%= form_for([#post, #post.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #comment %>
<div class="field">
<%= f.label "Name" %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit "Add Comment!" %>
</div>
<% end %>
And here's my comment partial:
<p>
<strong><%= comment.name %></strong><br />
<%= comment.created_at.try(:strftime, "on %A, %B %d %Y at %H:%M:%S") %><br />
<%= simple_format(h(comment.body), :sanitize => true) %>
</p>
In your form when you return from an error.
<% if #comment.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

Resources