Ajax Posting via jQuery to custom controller method not working - ruby-on-rails

I'm having an issue posting data to my custom controller methods via a jquery ajax post.
I have the following rails myPlayer.erb.html:
<% form_for #playersonline, :url => game_index_path, :html => { :method => :put, :class => "block", :id => "playersOnline_form" } do |f| %>
<% #playersonline.each do |member| %>
<li>
<div class="playerDetails">
<div class="playerNickname"><%= member.nickname %></div>
<div class="playerPlayLink">
<input type="button" class="submit_button playPlayer" id="<%= member.nickname %>" value="Play" />
</div>
</div>
</li>
<% end %>
<p class="morePlayers">
View more players >>
</p>
<% end %>
The forms html looks like this when rendered:
<form accept-charset="UTF-8" action="/game" class="block" id="playersOnline_form" method="post">
And the following jQuery code that attaches event handllers to each button.
SITE.Game = function() {
$('.playPlayer').live('click',
function() {
SITE.Game.sendGameRequest()
}
);
}
SITE.Game.sendGameRequest = function() {
$.post('/game/test,{"testData": "One", "testDataAgain": "Two"}, function(result) { console.log("data returned = " + result); }, "json")
}
So when I click a button, and the event fires making the ajax request I get the following error back:
Started POST "/game/test" for 127.0.0.1 at 2011-03-13 00:05:59 +0000
ActionController::RoutingError (No route matches "/game/test"):
My controller looks like this, and I can see from the server output that its not going into my test method:
class GameController < ApplicationController
def test
puts "---------------------------"
puts "GAME TEST WORKING"
puts "---------------------------"
end
def index
#returnMember = ["Tom","Pete"]
respond_to do |format|
format.json { render :json => #returnMember.to_json }
end
end
end
I have the following in my routes also:
resources :game
Any ideas where I'm going wrong?
EDIT
In response to nzifnab reply. I added:
resource :game do
member do
post 'test'
end
end
But am now getting:
ActionController::RoutingError (uninitialized constant GamesController):
EDIT 2
Fixed above by changing controller to GamesControllor from GameController.
Now getting the error:
undefined local variable or method `games_index_path'
<% form_for #playersonline, :url => games_index_path, :html => { :method => :put, :class => "block", :id => "playersOnline_form" } do |f| %
>
See my controller at beginning of issue.
EDIT 3
Fix for Edit 2 is quite simple! Changed url to games_path

resources :game sets up a RESTful route for your controller which automatically enables the show, create, new, edit, update, and destroy actions. If you want it to hit the test action you need to do this in your routes file:
resource :game do
member do
post :test
end
end
Or if you don't need all of those other RESTful routes you can do this:
match 'game/test' => 'game#test'
That's for rails 3. In rails 2.3.x the resourceful way would be like this:
resource :game, :members => {:test => :post}
I believe
Rails also expects your controllers to be named in the plural format. So a file in controllers/games_controller.rb should have the class GamesController < ApplicationController as it's class contents.
I would juse rename the file and/or controller to match the convention. But if you really need to keep it named singular for some reason you can add this to your routes file:
resource :game, :controller => 'game' do
# Other stuff here
end
I think that would fix it. But it's more usual for people to just pluralize their controller names.

It's because of your data type. It depends what kinda datatype you want but this is how you could do html and json:
JSON example:
SITE.Game.sendGameRequest = function() {
$.post('/game/test.json,{"testData": "One", "testDataAgain": "Two"}, function(result) {
console.log("data returned = " + result); }, "json")
}
And HTML:
SITE.Game.sendGameRequest = function() {
$.post('/game/test.html,{"testData": "One", "testDataAgain": "Two"}, function(result) { console.log("data returned = " + result); }, "html")
}
then in your controller you need to check the format:
class GameController < ApplicationController
def test
responds_to |format|
format.html #need for ajax with html datatype
format.json #need for ajax with json datatype
end
end
end
Change log:
[changed] the paths for your ajax request
[added] responds_to helper in your controller
And don't forget to declare the route in your routes.rb:
map.resources :games

Related

Custom controller route to update column active to false

I am trying to link to a custom controller route action and I'm doing something wrong. I have a Document model that handles uploading documents to my CRUD app. I want users to be able to 'delete' something, but not actually delete it from the system, but rather update the column 'active' to false. Then if someone with admin privileges can go ahead an complete the deletion. This process is needed because the app gets audited and we do not want to accidentally delete uploaded files.
I can't get the custom update action (remove) to work. When I rake routes I see:
remove_documents PUT /documents/remove(.:format) document#remove
In my routes file (I'll a couple similar routes I'll want to add later so I used collection it up this way):
resources :documents do
collection do
put "remove", to: "document#remove", as: :remove
end
end
In the Documents index view:
<%= link_to remove_documents_url(document), :method => :put do %>
<span class="fa fa-trash text-danger"></span>
<% end %>
My Controller:
def remove
#document = Document.find(params[:id])
#document.active = false
#document.save
html { redirect_to(:back, :notice => 'Document was successfully removed.')}
end
The link works, but then I get the following error:
NameError at /documents/remove.75 uninitialized constant DocumentController
raise unless e.missing_name? qualified_name_for(parent, const_name)
end
end
name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
name_error.set_backtrace(caller.reject {|l| l.starts_with? __FILE__ })
raise name_error
end
# Remove the constants that have been autoloaded, and those that have been
# marked for unloading. Before each constant is removed a callback is sent
If you want the remove action on a specific Document, change the routes to :
resources :documents do
member do
put "remove", to: "documents#remove", as: :remove
end
end
which gives you : remove_document PUT /documents/:id/remove(.:format)
and use it like :
<%= link_to remove_document_path(document), :method => :put do %>
<span class="fa fa-trash text-danger"></span>
<% end %>

Ruby on Rails - Show method for a parsed JSON result

I am building a seemingly simple website for a visitor to get a status update on a selected data piece. The data comes from an external API. The gist of it is this: the visitor sees a list of the data names, clicks one, and is redirected to a partial with status update, either True or False.
My index method works very well, and iterates through the data names perfectly. I believe my routing (using the friendly_id gem) should work fine. However, I cannot figure out how to properly set up the show method.
Here is my code thus far:
Controller:
class DataController < ApplicationController
include HTTParty
attr_accessor :name, :status
def index
#response = HTTParty.get("api_url").parsed_response
respond_to do |format|
format.json { render :json => JSON.parse(#result, :include => { :data => { :only => [:name, :status]}}) }
format.html { render "index.html.erb" }
end
end
def show
#response = HTTParty.get('api_url').parsed_response
respond_to do |format|
format.json { render :json => JSON.parse(#result, :include => { :data => { :only => [:name, :status]}}) }
format.html { render "show.html.erb" }
end
#name = #response.find(params[:name])
end
end
View:
<% #response.each do |data| %>
<ul>
<li>
<%= link_to data['name'].upcase, name_path(#name) %>
</li>
</ul>
<% end %>
Routes:
Rails.application.routes.draw do
root 'data#index'
get '/:name' => 'data#show', as: "name"
end
All of this together brings up the following error:
ActionController::UrlGenerationError in Data#index
Showing /app/views/layouts/_header.html.erb where line #11 raised:
No route matches {:action=>"show", :controller=>"data", :name=>nil} missing required keys: [:name]
What I am trying to accomplish is to be able to route each iterated link as 'root/{data name}', pulling {data name} from the JSON result as a parameter, and then rendering a show page with the status update information. Clearly, I have no idea how to actually capture the "name" key from the parsed JSON result as a param for the show method. I have tried creating a data_params method to contain it, but it did not work. I have tried implicitly calling the param on the find method in show (as above), to no avail. I have even tried calling a new api scrape in a params method and trying to parse the results into that, and nothing.
I'm guessing it is either some very simple mistake I'm not seeing (is my link_to actually pointing the right direction? are my api calls and JSON parsing done correctly [yes, I know I should create a separate method or helper for the api call, but that hasn't been working out for me so far--I keep breaking the app]? is this link actually supposed to call from the index method still?), or else something a bit more out of my depth.
Any ideas on where to go from here?
In this view:
<% #response.each do |data| %>
<ul>
<li>
<%= link_to data['name'].upcase, name_path(#name) %>
</li>
</ul>
<% end %>
You're using #name but you never actually assign a value to it in your index controller method. As a result - it gets passed to the name_path function with a value of nil. That throws an error because your route definition requires a name.
I think you want something like name_path(data['name']) or something along those lines.

Using link_to to only call a function in rails when the link is clicked

I'm very new to rails. I'm trying to call a function check() only when a link is clicked, but the controller will also call the function every time the view loads.
Routes:
routes.rb
Rails.application.routes.draw do
get 'welcome/index'
resources :articles
Controller:
articles_controller.rb
class ArticlesController < ApplicationController
helper_method :check
def new
end
def create
#article = Article.new(article_params)
#article.save
redirect_to #article
end
def check
puts "check"
end
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
private
def article_params
params.require(:article).permit(:title, :text)
end
Model: article.rb
class Article < ActiveRecord::Base
end
View: index.html.erb
<h1>
<%= link_to 'Call on click', :onclick => check() %>
</h1>
If you want to call some route from a link_to try
link_to "Call on click", controller: "articles", action: "check"
and then just add a route get 'articles/check'
inside your click function add the following statement to prevent the controller's action to be invoked
function click(event){
event.preventDefault();
your previous app logic
}
In your routes.rb add this:
get '/articles/check' => 'articles#check', as: :check_article
Then in your view you should do something like this:
<%= link_to "Check article", check_article_path, remote: true %>
Notice the remote: option, it will tell rails to send the request via ajax instead of loading a new page (Im assuming this is the intended behavior).
Now, since you are sending the request via ajax, Rails should respond the request with some piece of javascript. Would be something like this in CoffeeScript:
#views/articles/check.js.coffee
$ ->
$("a[data-remote]").on "ajax:success", (e, data, status, xhr) ->
alert "Article was checked."
You're getting confused between sever-side (Rails) & client-side (JS) events.
Consider the following:
#config/routes.rb
resources :articles do
get :check, on: :collection #-> url.com/articles/check
end
#app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def check
# do something
end
end
The above will allow you to use...
<%= link_to "Check", articles_check_path %>
This will fire every time a link is "clicked", indeed it will cause your browser to take you to the new action / view you're trying to see.
The above is server side functionality. It's standard HTTP.
You're confusing the above with javascript:
#app/assets/javascripts/application.js
var check = function() {
// do something
}
The above is client-side only, and can only be called with the onclick / .on("click" event handler in javascript:
<%= link_to "Check", some_path, onclick: "return check();" %>
This is client-side, and only works with elements loaded into the DOM. It's typically used to give extra functionality to your application's front-end.

form submit in rails not working, possible routing/path error unsure why?

I am trying to submit a form in rails that is just a pdf uplaod (using paperclip). There is something wrong with either my form, controller or model and i am not sure which.
this is my form:
<%= form_for #yearguide, :html => { :multipart => true } do |form| %>
<%= form.file_field :pdf %>
<%= form.submit "Add Event", class: "btn btn-primary" %>
<% end %>
my controller:
class YearController < ApplicationController
def new
#yearguide = Year.create(year_params)
end
def create
if #yearguide = Year.save
redirect_to '/'
else
render 'new'
end
end
my model:
class YearlyGuide < ActiveRecord::Base
has_attached_file :pdf
validates_attachment :document, content_type: { content_type: "application/pdf" }
end
my routes:
resources :year
I add the file and press upload, but I am being redirected to 'update.html.erb'.
The file doesn;t exist in the db, just an empty record.
When i debug the params on pressing uplaod I get this output
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"G7ZrXEiip/gsqhDObcfYhTT9kerYZGk+Zl29kWA5jos=", "year"=>{"pdf"=>#<ActionDispatch::Http::UploadedFile:0x000001029b0340 #tempfile=#<Tempfile:/var/folders/ns/ry6z7jfd6qg6j8xr2q6dw0yc0000gn/T/RackMultipart20140609-21455-1eg1sk3>, #original_filename="Artsmill Hebden Bridge Exhibition Programme 2014.pdf", #content_type="application/pdf", #headers="Content-Disposition: form-data; name=\"year[pdf]\"; filename=\"Artsmill Hebden Bridge Exhibition Programme 2014.pdf\"\r\nContent-Type: application/pdf\r\n">}, "commit"=>"Add Event", "action"=>"update", "controller"=>"year", "id"=>"9"}
=========================
EDIT
OK, so discrepancies with my naming led to the previosu errors, i started again, generating:
rails g model YearlyGuide pdf:attachment start:datetime end:datetime
rails g controller YearlyGuide new index show
now in my routes i have added
resources :yearly_guides
when i visit
/yearly_guides/new
I get this error
uninitialized constant YearlyGuidesController
I am really at a loss as to what I am doing wrong, I have done this before and never had these issues.
#iceman, thanks for your help and patience thus far.
The controller is not doing what it's supposed to do. This is the bare bones basic scheme of creating a new object in Rails.
class YearsController < ApplicationController
def new
#yearguide = Year.new
end
def create
#yearguide = Year.create(year_params)
if #yearguide.save
redirect_to '/' # I would consider redirect_to #yearguide to show the newly created object
else
render 'new'
end
end
end
EDIT:
You have to update your routes.rb to
resources :years
Since you are creating the yearguide object, rails infer that you have to do put/patch request, so request is going to update since rails getting id.
You have two options.
1) Change new method of controller like below
class YearController < ApplicationController
def new
#yearguide = Year.new
end
end
2) Override the method parameter by passing method params as 'post' inside your form tag

to get data from a method in controller and display it in view

I have written a method to count the vote for particular section and to display it in view file for section. But when I call this method count is not incremented. Should i make any changes in following method
code for voteme method in controller is as:
def voteme(num)
#section = Section.find(params[:id])
#section.vote += num
end
and code in view file is
<%= link_to "up", :url => voteme_section_path(1), :html => { :method => :post }%>
also can anyone suggest me the code to display updated count value.I have a vote field in section model.
In your view file
<%= link_to "up", voteme_section_path(1), :method => :post %>
But I have a question, you are voting up against a section. So why you are passing 1 to it. you should pass the section object if you would have stored it in #section variable. So its better you can modify the link as
<%= link_to "up", voteme_section_path(#section), :method => :post %>
In your route file I guess you need to do some thing like this
resources :sections do
member do
post 'voteme'
end
end
And in the sections controller, 'voteme' action
def voteme
#section = Section.find_by_id(params[:id])
unless #section.blank?
#section.update_column('vote', #section.vote + 1)
else
flash[:notice] = 'Sorry something goes wrong'
end
redirect_to your-path-that-you want-to-show.
end
Try adding #section.save after you change the value.
This logic should also be in the model, rather than in the controller. The controller should only pass things back and forth between the model and the view.
def voteme(num)
#section = Section.find(params[:id])
#section.update_attribute('vote', #section.vote+1)
end

Resources