getScript jQuery path not working / Ruby on Rails - ruby-on-rails

I've got a jQuery function that is called after a doubleclick on a list item.
app/assets/javascripts/tile/tile.js
$('#list > li').dblclick(function(){
// styling
$(this).toggleClass('liked');
// pass ID to controller
var movie_id = $(this).attr("data-id");
$.getScript("/likes.js");
});
Next to applying some new formats to said item my main goal is to make a database entry from my like controller. In this Railscast the index action from their comments controller gets called with this simple line.
$.getScript("/comments.js");
Additionally some JavaScript gets called from a index.js.erb file.
My first problem with understanding the example code from Railscasts is how they define the action. If I wanted to call the action createLike from my likes_controller how would I call it?
Secondly, my attempts so far have all failed because both the JavaScript file doesn't load and the action doesn't get called aswell.
Somehow I sense that I've messed up with the paths. Where should I locate the JavaScript files that should get called with the getScript function?
Files
app/assets/javascripts/likes/index.js.erb
console.log("Test");
app/controllers/likes_controller.rb
class LikesController < ApplicationController
protect_from_forgery
def index
Like.create(:user_id => current_user.id, :item_id => params[:id])
end
end

I believe the execution issue can be solved by moving index.js.erb from
app/assets/javascripts/likes/index.js.erb
to
app/views/likes
This is where Rails looks for templates to render (your script shouldn't be served by the asset pipeline). Rails tackles this through convention - your app automatically routes /likes to the index action.
If you want a more informative route, use the Rails routing guide to generate a new route and match it to the create_likes action in the Likes controller. Then,
$.getScript("/create_likes.js")
will know where to look

You can define action in controller like that:
class LikesController < ApplicationController
# another code
def createLike
# your action code
end
# another code
end
And you can call action like /likes/createLike.
In the folder PATH_TO_APP/app/views/likes create a file createLike.html.erb - there is will be a createLike view
Javascript files must be in the folder /PATH_TO_APP/public/javascripts
And best way to include javascript file is a javascript_include_tag like:
<%= javascript_include_tag "tile/tile.js" %>
tile.js file must be is into the /PATH_TO_APP/public/javascripts/tile directory.
And if you want to get javascript files with jQuery, you must put them in public/javascripts directory and call $.getScript('/javascripts/likes.js'); - there is an example.
P.S. I advise to look at getting started guide

The behavior you're wanting is different than what that specific Railscasts is addressing. It is specifically focused on the retrieving of new comments as they are created, without a page refresh. That is why you are running into issues following this guide.
First you will need to make sure you have a resources :likes in your config/routes.rb. From your code excerpt it looks like you are associating a like with a movie so make sure you make the route nested inside your resources :movies call. In the end your routes should look something like this:
resources :movies do
resources :likes
end
For the controller piece you will need to add a 'create' action to your controller. Assuming that your Movie model has_many :likes this is a simple version of what your action should look like:
def create
movie = Movie.find(params[:movie_id])
movie.likes.create(user_id: current_user.id)
end
You will also need to change your javascript code to make a post instead of a get request. That's because the http method is how Rails differentiates between a create and an index request as they both use the same url path (e.g. /comments.js). You will also need to have the url reflect that it's a nested resource within a movie. Here is modified version of your JS code with that change:
$('#list > li').dblclick(function() {
// Cached jquery this selector.
$this = $(this)
// pass ID to controller
var movie_id = $this.data('id');
$.post('/movies/' + movie_id + '/likes.js', function() {
$this.toggleClass('liked');
});
});
In regards to your .js.erb file, as stated by others, it should be placed in your app/views folder. However, due to your regular JS handling the logic you don't need to have it all.
This is just one strategy but there are quite a few other ways to handle JS interaction with Rails. If you want an example of using a js.erb (js.coffee in this case) view file you can take a look at this implementation. In that case all that is handling the click event is a link_to with the remote: true option which delegates it the jquery-ujs adapter.
Hope that helps!

This might not be close to your answer but I use $.getscript() to load those js/css files that i need once my page has rendered,which in turn improves the performance and reduces the page load time.This is the code I have used in my erb files.My shop_for_free_module.js resides in app/public/javascripts
<script type="text/javascript">
jQuery(document).ready(function($){
//this gives your protocol-http
var protocol = this.location.protocol;
//this gives your domain name-myshopptinsite.com
var host = this.location.host;
var initial_url = protocol + "//" + host;
$.getScript(initial_url + "/javascripts/eshop_js/shop_for_free_module.js");
});
</script>
...hope it helps.

try this out
Question: My first problem with understanding the example code from Railscasts is how they define the action. If I wanted to call the action createLike from my likes_controller how would I call it?
Answer:
class LikesController < ApplicationController
def create_like
Like.create(:user_id => current_user.id, :item_id => params[:id])
end
end
in routes.rb file
get '/create_like.js' => 'likes#create_like'
Question: Secondly, my attempts so far have all failed because both the JavaScript file doesn't load and the action doesn't get called aswell.
Anaswer: move app/assets/javascripts/likes/index.js.erb
code to
app/views/likes/create_like.js.erb
you need to pass item_id to
getScript method
$(document).ready(function() {
$('#list > li').dblclick(function(){
// styling
$(this).toggleClass('liked');
// pass ID to controller
var item_id = $(this).attr("data-id");
$.getScript("/create_like.js?item_id=" + item_id);
});
});

Related

How to add a custom route, controller, and action in Ruby on Rails?

I have a Ruby on Rails and ActiveAdmin application. I didn't basically change any default configuration except adding and registering a few models.
I want to enable my application with a route like GET /heartbeat and respond with a simple string to client/user. I'm wondering how could I do the following steps:
Add a custom route to my routes.rb file.
Add a custom controller under app/controllers path.
Implement a custom action and respond to user directly without any view.
routes.rb:
get 'heartbeat' => "custom_controller#heartbeat"
custom_controller.rb:
class CustomController < ApplicationController
def heartbeat
render inline: "Some string to the client/user"
end
end
Avoiding the Rails render stack will save you some processing and be faster. You can do this at the router level via a simple Rack "application" that returns a response code:
get 'heartbeat', to: proc { [204, {}, []] }
Anything that responds to call and returns [status, headers, body] is rack compliant so you can leverage a proc to do just that, right in the router. In this case, we send a 204 No Content which should be sufficient for a heartbeat, but you can always return custom data/headers.
Update:
I can only imagine that this was downvoted because people don't understand why this is better. Here's a quick attempt to explain:
In case it wasn't clear, you don't need a controller action at all with this method. Here's the equivalent solution to the accepted answer:
get 'heartbeat', to: proc { [200, {}, ['Some string to the client/user']] }
Sticking that line in your Rails routes.rb file will be equivalent to creating a new controller, view and route entry, with one key difference: It avoids the Rails response rendering stack so should be much faster than the accepted solution.

Rails controller action duplication

I have a controller show action which does some stuff and renders a view but due to some custom routing, I need a totally different action in a totally different controller to perform the same stuff and render the same view.
I don't really wish to duplicate the code. Is there somewhere I can put it and call it from both locations?
Edit:
I basically need to run the following from Collection#Show AND also from Gallery#SplitUrl:
#collection = Collection.find_by_id(params[:id])
if #collection.has_children?
#collections = #collection.children
else
redirect_to [#collection, :albums]
end
I cannot just redirect_to Collection#Show at the end of Gallery#SplitUrl as the redirect causes my custom URL's to be lost as it's a new request.
You could put the view content into a partial (/app/views/home/_example.html.erb) and then use the render "example" command in the HomeController.
The "some stuff" code you talk about could be put into a helper file /app/helpers/... to save you from duplicating code in the two separate controllers although it could depend on what the code is trying to do in the first place.
http://guides.rubyonrails.org/layouts_and_rendering.html
This might provide more information on the subject in general.
I think the simplest approach would be to add a route definition for your new url and map that to your existing controller's action.
Something like follows:
# config/routes.rb
# Existing resource
resources :foos
# The resource in question
resources :bars do
get :show, controller: 'foos', action: 'show', as: bar_foo_common_show
end
Note that this will give you /bar/:id, where id represents a bar resource. So in your foo#show action, your finder needs to be executed on appropriate class. This is when a few lines of hacky codes get added, for e.g. checking for request referer.
I think moving the common code to a function in possibly application_controller and calling that function from both show action would be cleaner approach, but based on my understanding you already have a similar scenario except for the common code in application_controller, and would like to try out a different approach!

Scope or ajax for queries

I am not to sure i understand correctly scope in rails. Here what i am trying to do I have a model call article and called tags.
To start off the application it log you in at Article#index action which show all articles. However what I want to be able to refine my view by clicking on a tags that would dynamically be created. The query i would like would be Article.find(:all, :conditions => ['tags = ?', 'world'])
How can i achieve this? Or should i just use ajax to do this?
I think ajax makes sense in this case.
You could have something like this.
routes.rb
match "/articles/tag" => "articles#tag"
articles_controller.rb
def tag
#particularly_tagged_links = Link.find_all_by_tags(params[:tags])
end
application.js or wherever you are using jquery codes. And trig this function when the user clicks the tag or something.
function taggit(tag) {
$.ajax({
url: "articles/tags?"+tag
});
}

How to pass a param from one view to another in Ruby on Rails, using POST

I feel like this should be an easy thing to figure out, but I'm stumped.
I have a value in a Project's instance variable called ID. I want to pass that value to a new Photos page to associate each photo that is created with that specific project, but I don't want the Project's ID to show up in the visible query string.
I've tried using link_to and button_to, but (I suspect) since I'm using "resources :photos" in my routes, all of the requests that come to photo#new are being interpreted as GET instead of POST.
Helllllllllllllllp!
Thanks to anyone that can give me some insight, I'v been killing myself over this for the past hour or two already.
--Mark
The usual way to do this in Rails is to create a route that matches urls like this: /projects/4/photos/new. Doing something else is up to you, but Rails makes it really easy to do stuff like this. See more on routes in Rails 3.
Your entry in routes.rb should look something like this:
resources :projects do
resources :photos
end
Then in app/controllers/photos_controller.rb you'd have this for the "New Photo" form page:
def new
#project = Project.find_by_id(params[:project_id])
end
and this for the action that the form in app/views/photos/new.html.erb submits to:
def create
#project = Project.find_by_id(params[:project_id])
#photo = #project.photos.create(params[:photo])
end
Of course you'll want to have error handling and validation in here, but this is the gist of it. And remember, use GET for idempotent (non state-changing) actions (e.g. GET /projects/4/photos), POST for creating a new thing (e.g. POST /projects/4/photos), and PUT for updating an existing thing (e.g. PUT /projects/4/photos/8).

Identical Files behave differently due to link with controller

I am building my first app with ROR and stumbled upon a couple of problems due to my understanding of the MVC
I have a page to add a new item, and this works fine, rails magically hooks it up to the items controller and somehow by magic it knows to look in the method 'new' as the page is called new.
But this layer is confusing me, as i need to now create a different version of new, same functionality but with a different look so to use a different layout to application.html.erb
So i attempt to create a copy of new.html.erb and create bookmarklet.html.erb - both contain exactly the same code: a link to a form. but of course bookmarklet will error on me because it does not have that link in the controller - how do i 'wire' up bookmarklet so that i can call the new method and so that it can behave in a similar way to the identical new.html.erb
Also, how can i tell the new bookmarklet.html.erb to ignore the application.html.erb and get its layout from another file?
thanks in advance
The magic happens in the routes. Rails uses something called RESTful routes, which is taking HTTP verbs and assigning standard actions to it. the new action is a GET request in HTTP speak, and if you are using scaffolding or following REST, will have the ruby call to build a new object in the controller, as an instance variable so you can use it in your view.
You have to tell rails routes that you want to BREAK this arrangement and to let /items/bookmarklet be used in the controller.
In your routes.rb file replace resources :items with
resources items do
member do
get 'bookmarklet'
end
end
In your controller put:
def bookmarklet
#item = Item.new
render :template => "bookmarklet", :layout => "different_layout" # or you can put this on the top of the controller, which is my style, but whatevs.
end
You should look into partials, if you are doing this as they clean up your code immensely.
A better way to think of things is to start with the controller instead of the view html.erb files. So each public method in your controller is effectively a page or action in the site. When you need a new action or page, add the method to the controller first. Then create the relevant view files.
So in your controller you'll need something like:
def bookmarklet
#item = Item.new(params[:item])
#item.save
render :template => "items/bookmarklet.html.erb", :layout => "different_layout.html.erb"
end
Normally you don't need to call render manually in the controller, but since you want a different layout than the default you need to specify it using render.

Resources