Correct way to use Ajax with rails - ruby-on-rails

I am trying to add ajax to a voting system but having difficulty targeting individual elements with jQuery. This is what i have so far:
Vote Link in index action
<%= link_to post_votes_path(post), :method => 'post', :remote => true do %>
<span class="score"><%= post.votes.size %></span>
<% end %>
Create action in Vote controller
def create
#post = Post.find(params[:post_id])
#vote = #post.votes.create
respond_to do |format|
format.html { redirect_to root_url }
format.js
end
end
jQuery in votes#create view (create.js.erb)
$('.score').html("I voted");
Trouble is when i click the link to vote it changes the html for all posts not just the post i tried voting on. Dont have much experience with jQuery so i cant help but think i am missing something obvious. Any ideas ?

all your spans have the .score class. that's the reason for all be changed.
This is a possible solution.
Change in your html:
<span class="score p_<%= post.id%>"><%= post.votes.size %></span>
And then change in your create.js.erb
$('.score.p_<%= #post.id %>').html("I voted");

I typically just use JQuery's $.post. I am using asp.net, but assume rails will work with that as well.
$.post("/someurltoyouraction", {myval:val},function(data){
// do stuff after post
});
This will produce an Ajax post request. You can define your post parameters in the {myval:val} object to match your requirements. It's essentially a key value definition based object {key:value}

Related

Rails Wicked Gem - Understanding routing

Okay, so I'm not really understanding nested routing in the wicked gem.
So far I have this. I'm not sure if everything is in the right folder or if I'm doing that right.
routes.rb
resources :events
resources :events do
resources :build, controller: 'events/build'
end
controllers/events_controller.rb
def create
#event = Event.new(event_params)
if #event.save
flash[:success] = "Event Created!"
redirect_to event_build_path(event_id: "event", id: #event.id)
# previously had redirect_to event_build_path without parameters)
else
render 'new'
end
end
controllers/events/build_controller.rb
class Events::BuildController < ApplicationController
include Wicked::Wizard
steps :details, :visibility
def show
#event = Event.find(params[:event_id])
render_wizard
end
end
views/build/details.html.erb
<%= form_for #event do |f| %>
#blab blah
<% end %>
I had the event_build_path without parameters at first and I had this error
No route matches {:action=>"show", :controller=>"events/build"} missing required keys: [:event_id, :id]
Had influence from this Rails wicked gem redirect with params but don't entirely understand the routing
I don't have an event_id set and I don't really understand how wicked keeps track of the step of via the id (or if its event_id).
As my object (event) is not created yet, what is "event_id" and the id at the end represent?
Not really an answer, but some clarifications. The thing you're trying to do is pretty hard, and requires a bunch of customizations to suit your own case. If you're not comfortable with wicked, or if that tutorial is nearly incomprehensible, it might be better to skip doing a wizard for now and come back and try it again in a month or so once you've had time to meditate on it.
Form
This is your wicked form
<%= form_for #event do |f| %>
#blab blah
<% end %>
Wicked works by doing two things, storing state in your url domain.com/build_pah/<step> and providing you with helper methods to easily manipulate the current state. Once you render the form you need to tell the browser where to submit info to when enter is pressed. Right now it is going to #event path, which isn't what we want. Instead we need to do something like:
<%= form_for #event, :url => wizard_path, :method => :put do |f| %>
<% end %>
This tells the form to go to the wizard_path url, this is a helper we provide. It also tells the form to submit using the PUT HTTP method, which should trigger your def update action inside of your Events::BuildController if it is set up correctly. On another note it doesn't look like Events::BuildController has an update action.
Event Controller
Your event controller looks fine, however you're redirecting
redirect_to event_build_path(event_id: "event", id: #event.id)
Wicked needs the id parameter to be the step you want to go to. So it should be:
redirect_to event_build_path(event_id: #event.id, id: :details)
or
redirect_to event_build_path(event_id: #event.id, id: Wicked::FIRST_STEP)
You can also get fancy and redirect to the index action which will do another redirect to the first step, but i always prefer being explicit.
Other Questions
Here is someone with a similar question: https://github.com/schneems/wicked/issues/141 take a look at their code, and their question. Try to understand what was wrong and how it was fixed. Then compare between what they're trying to do and what you're trying to do.
This question
It's hard to be more helpful without an explicit question. Breaking it down into I did this => I expected this => I got this instead , I tried to debug using this . Anywhoo, hope some of this was helpful. Maybe spin up another Rails example app and try to walk through my wicked tutorial in the readme, it will give you some more experience with what wicked does (and doesn't) do for you.

When submitting form for a new object - going to another route

I have a question regarding the submissions of forms in rails.
I have a form:
<%= form_for Event.new, multipart: true, class: 'form' do |f| %>
In the controller:
def create
#event = Event.new(event_params)
if #event.save
redirect_to dashboard_event_path #event
else
flash[:error] ||= 'Please fix the event\'s details'
render :new
end
Working on a new Event object. (i.e. /events/new)
However, when I'm posting that form, and there are validation errors, it will render that form again, but the url will be /events/. is that normal? I know that the routes for new is /new and create is POST to /events, but how do I keep the browser in the /new url?
Help?
Thanks
It's perfectly normal, nothing to be done here. Making the URL stay the same would be changing how Rails works internally - it's really not worth doing that.
That's normal. You are responding from the events method in the controller. Just because you got the html from a file with another name doesn't mean the url will change. If you want the url to change, the easiest thing to do would be to redirect to the new page instead of rendering it

ruby on rails implement search with auto complete

I've implemented a search box that searches the "Illnesses" table and the "symptoms" table in my DB.
Now I want to add auto-complete to the search box.
I've created a new controller called "auto_complete_controller" which returns the auto complete data.
I'm just not sure how to combine the search functionality and the auto complete functionality: I want the "index" action in my search controller to return the search results, and the "index" action in my auto_complete controller to return the auto_complete data.
Please guide me how to fix my html syntax and what to write in the js.coffee file.
I'm using rails 3.x with the jquery UI for auto-complete, I prefer a server side solution, and this is my current code:
main_page/index.html.erb:
<p>
<b>Syptoms / Illnesses</b>
<%= form_tag search_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %> <br/>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
</p>
auto_complete_controller.rb:
class AutoCompleteController < ApplicationController
def index
#results = Illness.order(:name).where("name like ?", "%#{params[:term]}%") + Symptom.order(:name).where("name like ?", "%#{params[:term]}%")
render json: #results.map(&:name)
end
end
search_controller.rb:
class SearchController < ApplicationController
def index
#results = Illness.search(params[:search]) + Symptom.search(params[:search])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #results }
end
end
end
Thanks, Li
I have had the same problem and had to create this gem for it: https://github.com/rayasocialmedia/rails_autocomplete
Here's how to do dynamic typeahead in Twitter-Bootstrap; I'm sure it's something similar for jQuery:
https://gist.github.com/1848558
Essentially, by listening to to non-navigational keystrokes, it triggers an AJAX partial text search to your controller. This return data then populates the JS framework's typeahead/autocomplete data to be displayed. This means that you really only need the one SearchController.
Try rails3-jquery-autocomplete. I am using it and had the same requirements as you, and they work fine together. Let me know if you need further help.

render :new not going to the right place after a validation

I have a 'new' form that gets validated in a post model. When the validator kicks in, it renders incorrectly.
The new post page path is at '/posts/new'
On validation, the new post page path is at '/posts' .. I need it to go back to '/posts/new'.
This is my controller:
def create
#post = current_user.posts.build(params[:post])
if #post.save
redirect_to public_post_page_path(#post.public_url)
else
render :action => :new
end
end
I have a feeling it might have to do with my form. So here is the formtastic first line:
<%= semantic_form_for [:student, post], :html => {:id => "post_form"} do |form| %>
This is the correct behavior from rails.
In the create action it simply renders the "new" view file. As such the url will be /posts but the view will correctly display the form. There is nothing wrong with this behavior; and in general rails convention is good form. Also the built in rails errors work if you just render new; however if you redirect they won't display.
If you really feel like you want to go back to that url you need to use:
redirect_to
instead of render.
If validation fails, user should see the form with the errors and stay at /posts/new. That's what you want, right?
There's a simple way to achieve this.
Set remote: true on the form to prevent the url from advancing. Handle ajax:success to replace the form on the page with the newly rendered one.
$('form[data-remote=true]').on 'ajax:success', (e, data, status, xhr) ->
if isHTML(data)
thisForm = "form[id=#{#getAttribute('id')}]"
$(thisForm).replaceWith $(data).find(thisForm)
isHtml() function is from this question.

form_tag action not working in rails

I have this form in my application.html.erb.
<%= form_tag(:action=>"index", :controller=>"posts") %>
<p>
// code here
</p>
I dont understand why is this getting directed to posts->create instead of posts->index?
Thanks.
Basically, Rails observes and obeys "RESTful" web service architecture. With REST and Rails, there are seven different ways to interact with a server regarding a resource. With your current code, specifying the form's action as index doesn't make sense: Rails' form helpers can either POST, PUT or DELETE.
If you wanted to create a post, then redirect to the index, you can do so in the applicable controller action:
class PostsController < ApplicationController
...
def create
#post = Post.new
respond_to do |format|
if #post.save
format.html { redirect_to(:action => 'index') }
end
end
While your form would look like:
<% form_for #post do |f| %>
# put whatever fields necessary to create the post here
<% end %>
You seem to be a little mixed up with respect to the uses for each action. Here's a quick summary of typical RESTful usage:
Index -> view a list of items
New/Edit -> form where items are added or edited
Create/update -> controller action where items are created/updated
The reason your routes file is not taking you to index is because index is not an action where posts are typically created or updated. The best way is to go RESTful. Unless you have a very unusual situation, the best way to set your system up is probably a little like this:
# routes.rb
resources :posts
# application.html.erb (or better: posts/_form.html.erb).
<% form_for #post do |f| %>
<% end %>
# posts controller, whichever action you want to use
def new
#post = Post.new
end
By putting the form in a partial called form you can access it in new, edit, or wherever else you need to manipulate a post in your system.

Resources