I'm using Pusher to add real-time page updates to my Rails app.
Here's a brief synopsis of how Pusher works (and later I'll show you what I'd like it to do):
Controller:
class ThingsController < ApplicationController
def create
#thing = Thing.new(params[:thing])
if #thing.save
Pusher['things'].trigger('thing-create', #thing.attributes)
end
end
end
Javascript (in <head>...</head>):
var pusher = new Pusher('API_KEY');
var myChannel = pusher.subscribe('MY_CHANNEL');
myChannel.bind('thing-create', function(thing) {
alert('A thing was created: ' + thing.name); // I want to replace this line
});
I want to replace the commented line with an ajax request to trigger some unobtrusive JavaScript. Assume I have the file app/views/things/index.js.erb:
$("things").update("<%= escape_javascript(render(#things))%>");
What should I write in the myChannel.bind callback to trigger the above code to execute?
You are not really comparing apples-to-apples here.
You are comparing the template rendered in an XHR request to things/index to the attributes of the #thing object from a POST to things/create.
You need to process the thing object that gets returned from Pusher in the web browser and modify the DOM accordingly.
Or, an easier solution would probably be to have your controller send formatted HTML to Pusher instead of object attributes. Then your javascript code could just insert the formatted HTML instead of trying to parse the thing object and modify the DOM manually.
Response to #user94154's comment:
DISCLAIMER: I never heard of Pusher until your question.
This does create a challenge b/c typically your HTML is formatted in the view, but you have to send data to Pusher from the controller. I can think of a few ways to do this:
If it isn't much HTML markup, you might want to break the "Don't Repeat Yourself" rule and repeat the HTML markup in your controller and send that to Pusher
If it is a lot of markup, I would abstract my view generation code to helpers. You can call a helper from your controller, too.
On the client side, you should have an empty div (or some DOM element) that can hold the HTML from Pusher. And do something like this:
myChannel.bind('thing-create', function(thing) {
$("div#thing_holder").html(thing.html);
});
http://blog.new-bamboo.co.uk/2010/5/12/integrating-pusher-into-a-complex-app-in-one-day
A little over my head, but I think it may put you on the right track.
pjax might be what you are looking for. Included in the README is how to get started with it in Rails.
I understand, here is how you do it...
Tried writing it on here but the code indenting, etc doesn't work well for longer stuff...
http://jbeas.com/ruby-on-rails/rails-3-pusher-app-and-unobtrusive-js/
Related
I have this webshop, and on one page you see
products;
with a submitting form for a booking;
your order with its bookings;
with a removing link for a booking;
and an updating form for a booking.
Both the order.bookings and the products make potentially long lists on a html page.
The whole booking works by only a booking_controller.
What the booking_controller does:
Takings in the (new) params of a single booking or the destroy action.
Saves the new order.
Redirects to the store.
Works fine, just using ruby and html.erb.
Only problem, and this really needs to change, is that obviously after each redirect the browser goes to the top of the page. The browser isn't focussed. Or better to say, the browser should remain, but doesn't.
I get that your doing all these things on the server-side, so a page reload, or better to say, data-refresh, is necessary. What I don't want is building this whole thing again on the client-side (JS).
Can't I simply say something like: after data refresh redirect to exact same spot on page. Ignoring all the difficulties an asynchronous request would give, or am I exaggerating and is a little JS easy?
With Rails, using ajax is very easy however if you're not familiar with ajax at all it can be a bit daunting at first. Luckily there are many tutorials on the subject. Basically, add the remote: true option to your form_for statement and rails will automatically understand you want it to make a 'POST' request in JS format. It's important to realize that the incoming HTTP request is in JS format because you'll then need to specify handling that event in the controller. Such as:
def create
#Do whatever saving and processing you need here
respond_to do |format|
format.html { redirect_to some_path_here }
format.js { } #By not adding anything in the brackets here, you're telling rails to fetch a js view file that follows standard rails convention and so it should be named 'create.js.erb'
end
Then in your controller's views folder create the view file create.js.erb. In that file you'll want to refresh whatever part of the page needs updating which usually involves hiding the old div that was there and appending a partial in its place. I usually leave an empty div with an ID on the page (in this case your new_whatever_page.html.erb that I then call in the js.erb file to append a partial to:
In your create.js.erb add:
$("#the-id-of-the-div-in-your-new-view-page").html("<%= escape_javascript(render 'order_table') %> #This basically says, find the div on the current page with a matching id and then append the partial named _order_table.html.erb to it.
Now just make a partial named
_order_table.html.erb
in the same views folder and put whatever content you want to insert or update.
Is it possible to call a ruby helper method from within a js.erb file?
I have a helper in application_helper.rb called solve which makes a API call to a third party service, and they only have a ruby client.
The js.erb file isn't being run on the client side, it is being called from within a controller method and run server side as it is PhantomJS.
I call the JS file from the controller
Phantomjs.run('phantom.js.erb', url)
Then within the PhantomJS js.erb file I have tried
var response = '<%= solve(variable) %>'
which just sets the variable as the string <%= solve(variable) %>
I have also tried
var response = <%= solve(variable) %>
but that just seems to make the application hang and become unresponsive.
I have seen other questions similar to this. In those questions they are asking if it is possible to call it from client side JS which I know you need to use an ajax request to do so.
Is this possible?
Try this:
var content = '#{solve()}'
Need a bit more context for this question, but I'll try my best to answer:
Essentially, you wouldn't be able to access your application_helper methods outside of any .erb files. (ie. if you have application.js or any other js file in your pipeline and you are trying to <%= solve %> from there it wouldn't work - mainly because it isn't an .erb file)
There are a lot of ways and architecture to go about solving this, but here are two simple ones:
If you put the JS you want to evaluate inline on the same page as your partial/html.erb page by using <script> //JS ERB CODE GOES HERE </script> It will actually evaluate properly since it is inside of an erb file. However, this is generally looked upon as unclean...
What you probably want to do is pass the value (presumably) you want that comes from the "solve" application_helper in a 'data' attribute on the html element that it affects. By utilizing "unobtrusive javascript" in this way, you simply pass the value through markup and then in your JS you can get the variable by using jQuery code like this. Here's an example:
<%= link_to "test_link", root_path, :data => {:solve => solve } %>
Of course it doesn't have to be a link, any HTML element will do, and then in your jQuery:
$("#test_link").data("solve");
will return to you whatever output comes out of your "solve" method in the application_helper.
it can possible but there are different ways to do it. one way is define the method in helper_method in your controller and call it from your view. and another way is use the gon gem to access some controller value in your javascript. please check what is best for you please check the below links for more help
http://apidock.com/rails/ActionController/Helpers/ClassMethods/helper_method
https://github.com/gazay/gon
http://railscasts.com/episodes/324-passing-data-to-javascript
In rails i need to take a base64 string, and use it to generate a picture in rails. Now i'm having trouble, because i need to interact with AJAX calls (im strictly working on the server side, another guy is doing that client work) to send pictures. So far i've been taking requests in my application by having data transferred through the url (in the AJAX requests) but now im not sure if it's possible to transfer such a huge string through the url. How could i take in the data (like how could he pass it to me) to generate a picture.
Note: i've been using paperclip for my application so far, but now uploading through the form is not an option, it needs to be in an AJAX call where data is passed in a single call.
You're right, most browsers limit the length of a URL. The limit on IE8/9 is 2083 characters. Even if your particular browser has a higher limit, many servers limit the URL length as well (apache's default limit is right around 8k). It would be best to submit the image as a POST request with the data in the POST body.
I would use jQuery to POST JSON data to the server. In the controller, if this is set up correctly, you won't have to do a thing to parse the JSON. ActiveSupport will recognize the content type and parse it out into the params hash automatically.
Actually posting the data will depend on which javascript library you're using. Here's an example in jQuery, which you'd probably want to wire up to the onclick event of a submit button. This assumes you have a named route called process_image. This code would go in your view.
$.post(<%= process_image_path %>, { b64_img: "your_base64_image_data" });
In your controller, you can access the posted data with params[:b64_img]. If you want to return something from the controller back to the client, you can do this in the controller:
render :json => #model_object
And change the jquery call to look like this so you can do something with the return value:
$.post(<%= process_image_path %>, { b64_img: "your_base64_image_data" },
function(data) {
// do something with the data returned by the controller
});
Hope this helps. You can read more about the jQuery post call I used here: http://api.jquery.com/jQuery.post/
Dan
I am learning Ruby on Rails, and I am very confused on how the controller-model-view relationship works for my application.
What I have now is a table full of comments (posts) users have made. What I want to do is let users click on a comment to see more information in a separate panel (ie, other database fields that weren't initially shown, for example the user_id of the person who posted the comment).
In my _post.html.erb, I have something like:
<div class="post" id="<%= post.post_id %>" onclick = ?? >
<p>post.text</p></div>
What should go in onclick? I need a way for the onclick to call a helper/controller method which can load more information, and then put that in another div on a page (I've tried variations of using the controller and helper to call javascript which inserts html into the site, but that seems messier than it should be). From what I understand, I should create some kind of partial _postdetails.html.erb file that handles the actual displaying of the html, but I have no idea how to specific where that partial would go in the page.
Any help would be appreciated, thanks!
You can achieve what you want either by using Rails helpers or by writing the AJAX calls yourself.
Personally I manually write all my AJAX calls using jQuery.
You can also use Prototype which ships with Rails.
That being said you can do.
In your JS file :
$("div.some-class").click(function()
{
$.ajax(
{
url:"url/to/controller/action",
type:<GET>/<POST>,
data://If you wish to sent any payload
});
});
In your controller :
def some_action
#some computation
render :update do |page|
page["id_of_div_to_be_refreshed"].replace_html :partial => "some_partial"
end
end
It seems that with g:formRemote and g:submitToRemote, I can only specify one update target div. What would be a viable strategy for updating multiple divs?
if you want to stick with using the g:formRemote tags to perform your ajax, it might not be possible. Why not write some jQuery, and roll a custom ajax update? it couldnt be easier!
You could instead of using update, use onSuccess and parse the response and update the elements you need to update like this:
<g:formRemote name='loginForm' url="[action:'login']"
onSuccess='loginOK(e)' >
<!-- form fields -->
</g:formRemote>
<g:javascript>
function loginOK( resp ) {
// parse the resp.responseText and update
}
</g:javascript>
Or you could just use jQuery and roll your own like the previous answer suggests.
If you want to update one element based on success vs another on failure you can use a map like this:
<g:formRemote name='loginForm' url="[action:'login']" update="[success:'message',failure:'error']">
there is asolution to this grails problem, you can use taconite, where taconite allows to update muliple elements with one single ajax call
http://malsup.com/jquery/taconite/
and there is another solution posted at someone's blog, but my reputation does only allow me to post one link here on stackoverflow!!!
so i give the title of the blog post "Updating multiple page elements with Grails and Ajax"
From the grails doc for g:formremote, http://grails.org/doc/2.2.0/ref/Tags/formRemote.html , you can use the onSuccess callback to define a js function for a succesfull submit, so you can update all your target elements within that function, otherwise making an ajax call yourself also is a good option.