Rails, Edit page update in a window - ruby-on-rails

I have my code working so that I have a table of businesses. There's a pencil icon you can click on the edit the business information. The edit information comes up in a partial inside of a modal pop up box. The only problem is that once they make the changes they want and click update, it sends them to the 'show' page for that business. What I want to happen is have the pop up box close and have it update the information. This is my update function in my controller.
def update
#business = Business.find(params[:id])
respond_to do |format|
if #business.update_attributes(params[:business])
flash[:notice] = 'Business was successfully updated.'
format.html { redirect_to(business_url(#business)) }
format.js
else
format.html { render :action => "edit" }
format.xml { render :xml => #business.errors, :status => :unprocessable_entity }
end
end
end
I tried following railscast 43 and i created an .rjs file but I couldn't get that to work at all. My update was still taking me to the show page. Any help would be appreciated.
EDIT: Added some more code.
<% form_for(#business) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
...
<%= f.label :business_category %><br />
<%= f.select :business_category_id, #business_categories_map, :selected => #business.business_category_id %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<p>
<%= f.submit 'Update' %>
</p>
<% end %>
This is my form inside of my edit page which is being called through the index in a pop up by:
<div id="popupEdit<%=h business.id %>" class="popupContact">
<a class="popupClose<%=h business.id %>" id="popupClose">x</a>
<% if business.business_category_id %>
<% #business = business %>
<%= render "business/edit" %>
<% end %>
</div>

It's hard to say without seeing your form code (hint hint! :-), but it could be that you're using form_for (which will submit a POST as per normal html forms) instead of remote_form_for (which will send an AJAX request).

Gotta say, get your code to work without javascript first ... also, don't use RJS at all. Use unobtrusive javascript instead.
As Mr. Hyland says, we need to see your view code also before we can help any further.

Related

Check for result of verify_recaptcha in Ruby on Rails HTML file

I am trying to get a Boolean result from verify_recaptcha that is implemented my app controller.
Code from the controller:
def create
#render plain: params[:student].inspect
#student = Student.new(student_params)
if verify_recaptcha(model: #student) && #student.save
redirect_to #student
else
render 'new'
end
end
HTML code:
<h1 class="col-md-12">New Student</h1>
<div class="col-md-12">
<%= form_with scope: :student,url: students_path,local: true do |form|%>
<p>
<%= form.label :name %><br>
<%= form.text_field :name%>
</p>
<p>
<%= form.label :student_id,'Student ID' %><br>
<%= form.text_field :student_id%>
</p>
<p>
<%= form.label :course %><br>
<%= form.text_field :course%>
</p>
<%= recaptcha_tags%>
<p>
<%=form.submit 'Create Student'%>
</p>
<%end%>
<%= link_to 'Back', students_path %>
</div>
EDIT: Here is what I want to achieve when recaptcha fails.
So far, when the recaptcha fails, the webpage only reloads and doesn't go to the next page. What I want to do is create an alert indicating the number of errors. It turns out I am unable to use verify_recaptcha in the HTML. Any advice?
If you want to use the result of verify_recaptcha in the view, you could assign the result to something in the controller, maybe like this:
def create
#student = Student.new(student_params)
#recaptcha_succeeded = verify_recaptcha(model: #student)
if #recaptcha_succeeded && #student.save
redirect_to #student
else
render 'new'
end
end
Now in the view you should be able to refer to #recaptcha_succeeded.
However, by passing in a model to verify_recaptcha, an error should be added to the model as well, in this case in #student.errors. That information will also be available in the view. The docs on the recaptcha gem (https://github.com/ambethia/recaptcha) discuss this in more detail.

AJAX partial in loop

I am trying to render a partial with ajax when submitting a form.
Here is my code:
index.html.erb
<% #inbox.each do |conversation| %>
<div class="message">
<div id="messages">
<%= render conversation.messages %>
</div>
<div class="inner-message">
<%= form_tag({controller: "conversations", action: "reply", id: conversation.id}, {remote: true, method: :post}) do %>
<%= hidden_field_tag :recipient_id, current_user.id %>
<%= hidden_field_tag :subject, "#{current_user.name}" %>
<div class="form-group">
<%= text_area_tag :body, nil, class: "form-control", placeholder: "Odgovori" %>
</div>
<div class="form-group">
<%= submit_tag 'PoĊĦlji', class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
<% end %>
index.js.erb
$("#messages").html("<%= escape_javascript(render conversation.messages) %>")
conversations_controller.rb
def reply
conversation = current_user.mailbox.conversations.find(params[:id])
current_user.reply_to_conversation(conversation, params[:body])
respond_to do |format|
format.html { redirect_to messages_path }
format.js { redirect_to messages_path }
end
end
when I submit the form, I get an undefined local variable error:
ActionView::Template::Error (undefined local variable or method
`conversation' for #<#:0x007fd287172fa8>)
How do I pass the local variable from the loop to the .js.erb view?
Thanks!
I usually don't do much rendering of js in applications so I'm a bit rusty on the specifics. However there are a couple of problems with your code.
First by issuing a redirect your instructing the browser to load a new url . Any variables such as 'conversation' that you would have set would be forgotten.
As the Stan Wiechers alluded you need to use an instance variable (e.g. #conversation) if you want to preserve conversation for the view. Unfortunately that won't help you in this case because of the redirect which wipes out all variables not stored in the session, cookies, or flash hash.
What I think you want to do is render your partial in stead of redirecting. Typically when you are using ajax you don't want to reload the page on the server side. In Rails you would typically render json or in your case a js partial.
Try
format.js{render partial:[PARTIAL NAME], locals:{conversation: conversation} }
This will render the partial without redirecting and will pass your local variable. If you change 'conversation', to #conversation then you can leave off the locals:{conversation: conversation} but your partial should reference
#conversation
not
conversation
hope that helps

Creating multiple entries on one model - Ruby on Rails (non nested)

I am having a difficult time finding information on this but think the solution is a simple one. In short, I need to have the ability to add multiple entries to one model at one time. The user story goes like this: User selects "Add New" and is directed to the page where they can add simply ONE entry or select a drop down of the desired entries they want to add.
All the posts I see have information about doing this with objects that are nested but I am just using one model. Do I need to follow the same protocol? Is there a simpler way? Am I just searching for the wrong terminology since being new to Ruby?
The basic application looks like this:
ticket_controller.rb
def new
#ticket = Ticket.new
end
def create
tnum = gets.chomp
tnum.times do Ticket.new(ticket_params)
respond_to do |format|
if #ticket.save
format.html { redirect_to #ticket, notice: 'Ticket was successfully created.' }
format.json { render action: 'show', status: :created, location: #ticket }
else
format.html { render action: 'new' }
format.json { render json: #ticket.errors, status: :unprocessable_entity }
end
end
end
new.html.erb
<h1>New ticket</h1>
<%= render 'form' %>
<%= link_to 'Back', tickets_path %>
I have looked throughout the site and just think I am missing something! Thanks for pointing me in the direction needed.
_form.html.erb
<%= form_for(#ticket) do |f| %>
<% tnum.times do |index|%>
<div class="field">
<%= f.label :type %><br>
<%= f.text_field :type %>
</div>
<div class="field">
<%= f.label :amount %><br>
<%= f.text_field :amount %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
There must be a better way, but this one way to do it. (Note I normally use a 'Form Object' but for this example I'll just use the raw collection):
In your controller change the object passed to the new form to be an array (in this case I'll pre-populate it):
def new
#tickets = [Ticket.new(title: 'New Ticket')]
end
Then in your new template you need to update it to iterate over the tickets array:
<%= form_tag tickets_path do |f| %>
<% #tickets.each do |ticket| %>
<%= fields_for "tickets[#{ticket.object_id}]", ticket do |builder| %>
<%= render 'ticket_fields', f: builder %>
<% end %>
<% end %>
<%= link_to_add_ticket "Add Tickets" %>
<%= submit_tag %>
<% end %>
The ticket fields partial looks like:
<fieldset>
<%= f.label :content, "Ticket" %><br />
<%= f.text_field :title %><br />
</fieldset>
For good measure add a helper to allow you to add new tickets dynamically:
module TicketsHelper
def link_to_add_ticket(name)
# create a new object for the form
new_object = Ticket.new
# get an id for javascript to hook into
id = new_object.object_id
fields = fields_for("tickets[#{id}]", new_object) do |builder|
render("ticket_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
and you need some coffee script to wire that up:
jQuery ->
$('form').on 'click', '.add_fields', (event) ->
time = new Date().getTime()
regexp = new RegExp($(this).data('id'), 'g')
$(this).before($(this).data('fields').replace(regexp, time))
event.preventDefault()
Basically all of this is an adaption of this railscast which might be helpful: http://railscasts.com/episodes/196-nested-model-form-revised however, that is dealing with the more classic nested model.
Couldn't you save the number of tickets the user wants to purchase to a variable, then pass that integer to a times loop? Like so:
#gets from form
ticket_buys = gets.chomp
ticket_buys.times do Ticket.new(ticket_params)

Rails Modal Form - Can't Get Validation Errors to Display in Modal

EDIT: I forgot to mention I am using validation at the model level, and that works fine. So the validations are preventing the modal form from being submitted (and ajax:error is getting called), but I'm having no luck dealing with the resulting errors object and properly displaying the errors. For now I'm just using placeholder text ("FORM HAS ERRORS"). Again, validations and displaying errors are working fine with my non-modal (non-ajax) forms (where I'm using the error messages partial). I really wish I could just render that partial in my modal dialog box, which you would think would be simple.
I'm pulling my hair out over this.
I have an "add tour" form, and within that form you can select buildings from the database to add to the tour (I'm using jquery tokeninput to search for and select buildings). All that works great.
I added the ability for the user to add a new building by providing a "Add Building" link, which brings up a modal form. I process the results and everything works great (building gets saved, modal gets dismissed, token gets added, etc).
Everything works great except validation in the modal form . . . which doesn't work at all. I've tried client_side_validations, I've tried writing coffee script to iterate through the error object returned by the controller, etc.
Anyway, I've tried everything I know to try, so now I'm coming to you guys for help. For now I just have placeholder error-handling code in the coffeescript file (that just displays "FORM HAS ERRORS" in a very rudimentary way). I took out all my previous attempts at making this work because it was getting ugly, and I'm really just looking for the best way to do this.
Here are the pertinent files.
building.js.coffee
$ ()->
$("form.new_building").on "ajax:success", (event, data, status, xhr) ->
$("form.new_building")[0].reset()
$('#new-building-modal').modal('hide')
fulladdress = "#{data.address} (#{data.name}, #{data.city}, #{data.zip})"
$('#tour_building_tokens').tokenInput("add", {id: data.id, address: fulladdress} )
$("form.new_building").on "ajax:error", (event, xhr, status, error) ->
$('#display_errors').append('<font color="red"><strong>FORM HAS ERRORS</strong></font><br><br>')
$('#display_errors').show()
buildings_controller.rb
....
def create
#building = Building.new(params[:building])
respond_to do |format|
if #building.save
format.html { redirect_to #building, notice: 'Building Created!' }
format.json { render json: #building, status: :created, location: #building }
else
format.html { render 'new' }
format.json { render json: #building.errors, status: :unprocessable_entity }
end
end
end
new.html.erb
<% provide(:title, 'Add Tour') %>
<h1>Add Tour</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#tour) do |f| %>
<%= render 'fields', f: f %>
<%= link_to 'Add Building', '#new-building-modal', 'data-toggle' => "modal" %>
</br>
</br>
<%= f.submit "Add Tour", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
<div id='new-building-modal' class='modal hide fade'>
<div class = "modal-body">
<%= form_for(Building.new, remote:true, html: {"data-type" => :json}) do |f| %>
<div id="display_errors" style="display:none;">
</div>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.label :city %>
<%= f.text_field :city %>
<%= f.label :zip %>
<%= f.text_field :zip %>
</div>
<div class = "modal-footer">
<%= f.submit "Add Building", class: "btn btn-large btn-primary" %>
</div>
<% end %>
</div>
Oh, and I also have a shared error messages partial that I'm not using with this modal right now (because I couldn't get the modal to "refresh" to display the errors). In a perfect world I'd use this same partial with the modal, because it works great with my other non-modal forms.
Here is the partial (again, not rendering this currently in the above code).
<% 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| %>
<% if msg != "Password digest can't be blank" %>
<li>* <%= msg %></li>
<% end %>
<% end %>
</ul>
</div>
Thanks in advance for any help anyone can provide. I need as much detail as possible. I've researched related questions on Stack Overflow, and every time I think I'm close, I come up empty.
Thanks to muttonlamb for pointing me in the right direction. I was 50% sure it had to do something with parsing the JSON, and he convinced me to stay on that path. Ironically it was this SO question that helped me get to the final answer. The answer to that question, which involved printing the error to the console, was what I was looking for. It turns out that it wasn't so much that I was parsing the error wrong . . . I was parsing the wrong object. Here is the final implementation that works . . .
new coffeescript (notice how I show, hide, and clear the div as necessary):
$ ()->
$("form.new_building").on "ajax:success", (event, data, status, xhr) ->
$("form.new_building")[0].reset()
$('#new-building-modal').modal('hide')
fulladdress = "#{data.address} (#{data.name}, #{data.city}, #{data.zip})"
$('#tour_building_tokens').tokenInput("add", {id: data.id, address: fulladdress} )
$('#error_explanation').hide()
$("form.new_building").on "ajax:error", (event, xhr, status, error) ->
errors = jQuery.parseJSON(xhr.responseText)
errorcount = errors.length
$('#error_explanation').empty()
if errorcount > 1
$('#error_explanation').append('<div class="alert alert-error">The form contains ' + errorcount + ' errors.</div>')
else
$('#error_explanation').append('<div class="alert alert-error">The form contains 1 error</div>')
$('#error_explanation').append('<ul>')
for e in errors
$('#error_explanation').append('<li>' + e + '</li>')
$('#error_explanation').append('</ul>')
$('#error_explanation').show()
new view:
<% provide(:title, 'Add Tour') %>
<h1>Add Tour</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#tour) do |f| %>
<%= render 'fields', f: f %>
<%= link_to 'New Building', '#new-building-modal', 'data-toggle' => "modal" %>
</br>
</br>
<%= f.submit "Add Tour", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
<div id='new-building-modal' class='modal hide fade'>
<div class = "modal-header">
<div id="error_explanation" style="display:none;">
</div>
</div>
<div class = "modal-body">
<%= form_for(Building.new, remote:true, html: {"data-type" => :json}) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.label :city %>
<%= f.text_field :city %>
<%= f.label :zip %>
<%= f.text_field :zip %>
</div>
<div class = "modal-footer">
<%= f.submit "Add Building", class: "btn btn-large btn-primary" %>
</div>
<% end %>
</div>
new controller:
def create
#building = Building.new(params[:building])
respond_to do |format|
if #building.save
format.html { redirect_to #building, notice: 'Building Created!' }
format.json { render json: #building, status: :created, location: #building }
else
format.html { render 'new' }
format.json { render json: #building.errors.full_messages, status: :unprocessable_entity }
end
end
end
Finally, to keep the modal from scrolling when the errors are added (I wanted it to auto-resize instead), I added this CSS:
#new-building-modal {
max-height: 600px;
}
Hope all these details prevent someone else from having to waste nearly a week on silly modal validation errors.
The issue looks like your ajax request error section does not run.
The reason is this, the error you're looking for would be something like 'page not found' or some other HTTP error.
In your controller, the HTTP request will still be successful, i.e. it will still return data.
Your logic for handling whether errors are present should be in the ajax success block.
Hope this makes sense
$ ()->
$("form.new_building").on "ajax:success", (event, data, status, xhr) ->
$("form.new_building")[0].reset()
$('#new-building-modal').modal('hide')
fulladdress = "#{data.address} (#{data.name}, #{data.city}, #{data.zip})"
$('#tour_building_tokens').tokenInput("add", {id: data.id, address: fulladdress} )
You need to be checking for the error variable in this section.

Displaying record count - Ruby on Rails - Ajax

I am new to rails so sorry if sometimes I don't make much sense. Here is what I am trying to do. I am trying to build a vote system. So next to a blog post there is a link that says 'vote' (will probably say like later). So far I have working: when the vote button is clicked, a value of '1' is delivered to the vote table and then that particular posts vote records display beneath the vote via AJAX (I copied a comment functionality). Instead of rendering all the number '1's below, I want it to render the updated count.
My vote table has the columns 'vote' and 'post_id' that are successfully being entered. My thinking was that I could just change my partial template to do this. Here is the code:
votes_controller:
class VotesController < ApplicationController
def create
#post = Post.find(params[:post_id])
#vote = #post.votes.create!(params[:vote])
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
end
def count
#post = Post.find(params[:post_id])
#vote = calculate :count
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
end
Here is the page where is is showing, /posts/show.html.erb:
<div id="backto"<%= link_to 'Back to all BattleCries', posts_path %></div>
<%= render :partial => #post %><br/>
<p5>Add a Comment</p5>
<div id="belt">
<div id="belttext">
<% remote_form_for [#post, Comment.new] do |f| %>
<p>
<%= f.text_area ( :body, :class => "commentarea") %>
</p>
<%= f.submit "Add Comment"%>
<% end %>
</div>
<div id="beltbottom">
</div>
</div><br/>
<br/><p5>Comment Stream </p5>
<div id="comments">
<%= render :partial => #post.comments %>
</div>
<p>
<% remote_form_for [#post, Vote.new] do |f| %>
<p>
<%= f.hidden_field :vote, :value => '1' %>
</p>
<%= f.submit "Vote" %>
<% end %>
<div id="vote">
<div id="votes">
<%= render :partial => #post.votes %>
</div>
</div>
</p>
Here is the :partial, /votes/_vote.html.erb: (this is where I thought I would just need to change it to vote.count, or post.count or something but can't get it to work).
<% div_for vote do %>
<%= h(vote.vote) %>
<% end %>
Here is the /votes/create.js.rjs file:
page.insert_html :bottom, :votes, :partial => #vote
page[#vote].visual_effect :highlight
I hope that all makes sense.
I think it's repeating because your .rjs is "inserting at the bottom" of the div instead of "replacing" ... you probably want page.replace_html
It would be better to have a DIV or SPAN tag that contains the number of votes for a post ... then have your .rjs file update the DIV's inner_html with the number of votes (which would be #post.votes.count) ... I don't think you really need a partial.
You probably want:
<%= #post.votes.count %>
You also probably want to use replace instead of insert_html - does that make sense? Insert is just adding more elements to the DOM whereas replace will replace the element.

Resources