RJS method outputting raw javascript - ruby-on-rails

I've got a page where I'm dynamically adding elements to a from a series of select boxes. I'm using RJS to do this and it's working great. Now, these elements in the div are a series of that are accompanied by Delete buttons, in case the user wants to remove a textarea. Here's where I'm hitting a wall.
Here's the code that runs the Delete button. This is working well to my knowledge:
<%= link_to image_tag("/images/button_delete.gif", :alt=>"Delete"), :controller=>"report", :action=>"remove", :id=>#sentence.id %>
In my report controller, I've got this very simple method being called by the above code:
def remove
#sentence_id = params[:id]
end
Again, I think that's working. Now, when I activate this action by hitting the button, off we go to the RJS file, remove.rjs:
page.remove 'sentence_'+#sentence_id
And here's what I get in my browser, instead of a happily removed element!
try
{
Element.remove("sentence_63");
}
catch (e)
{
alert('RJS error:\n\n' + e.toString());
alert('Element.remove(\"sentence_63\");');
throw e;
}
My understanding is that this happens when there's no page in the current context. Online documentation on this is kind of thin.
Any help appreciated!
Cheers,
Aaron.

Try link to remote. That will build the ajax call for you and should remove the element from the page.
Then link_to_remote syntax is slightly different than the link_to syntax, so don't let that trip you up either.

Since your remove function doesn't seem to actually delete a record, if you just want to remove an HTML element from a page you can use link_to_function with the Prototype remove() method for Elements. In addition, if you've got a recent version of Rails (for example, 2.3.2) you can take advantage of the dom_id helper to auto generate the sentance_id ID attribute
<%= link_to_function(image_tag("button_delete.gif", :alt=>"Delete"), "$('#{dom_id(#sentence}').remove();" %>
An approach like this could help keep the number of methods down in your controller (unless you intend on doing something else in the controller)

Your Delete link is setup as a normal link, i.e.
<a href="/report/remove" id="sentence_63">
<img src="/images/button_delete.gif" alt="Delete" />
</a>
which triggers a normal HTTP request. Since your intent is to trigger an AJAX request, try PJ Davis' recommendation and use link_to_remote

Related

Delete link behaviour lost when I regenerate HTML. How can I handle this?

If I regenerate a Rails delete link on my page, something like the following:
<a href="/categories/19" data-method="delete" data-confirm="Are you sure?" ..>Link</a>
When this page loads, something in Rails must set the behaviour of this link as I get a nice "Are you sure?" before I commit to delete something. However, when I regenerate the HTML I'm guessing I need to re-initialize the behaviour but I'm not sure where this comes from. Can anyone tell me if there is a function I should call again after I generate this HTML link? Thanks
If you mean that the "Are you sure?" pop-up message fails to work after you reload the page, the issue may lie with Turbolinks. Have a look at this discussion to see how to a). disable Turbolinks for individual links; b). disable it for the whole HTML document; or c). remove it from your Rails project entirely (probably without noticeable impact).
I suspect your problem lies in the javascript you use to set up the link. The sequence of events is something like this:
page loads
dom ready js runs and attaches onclick events to everything with a data-confirm attribute
some other js runs later and adds a new element with a data-confirm attribute. This doesn't have the onclick, because it wasn't in the dom when step2 happened.
One solution to this is to make sure that the js which sets up the links is in a function which can be called when you add the new element to the page. Then you can add a call to this to the js which adds the new element.
The gotcha with this is that you could end up re-adding the functionality to the elements that are already there, so that they now have two onclick events, each of which does the same thing (so it happens twice). To cope with this your code could avoid adding it to elements which already have that event, OR strip the event off all elements which would get the onclick, THEN apply the onclick.
Alternatively, you could set up the code to take an argument which is an selector, and it only applies the onclick event to elements **within* the element with the selector. So when you call it in dom ready you pass "body" and when you do it later you pass "#id-of-new-div-being-loaded" or something along those lines.
You can do this, this will turn off turbolinks for this particular URL only
<span data-no-turbolink><a href="/categories/19" data-method="delete" data-confirm="Are you sure?" ..>Link</a></span>

Call a controller method in a view using onclick option

Hi I have the following problem. I would like to call a controller method which executes some sql statements by onklick option of a button or a link.
So I got a method "publish" in my controller. It looks sth like this:
def publish
do execute sql statements
flash[:notice] = 'sql statements executed.'
end
And in my view I would like to have a button or a link to call this method like this:
<input type="button" onclick="<% controller.publish %>">
But I get the error:
undefined local variable or method
I also tried to route it to use this method as :action. That did not work as well. I searched now for a while and found some solutions by making this method a helper_method, though I get the same error again.
I'm pretty new to Ruby and Rails so I hope you can help me.
If, in your view, you try something like <% controller.publish %>, that will call the publish action when the view is rendered, not when a user clicks on the button.
You can do something like this:
Create a route which will invoke publish when requested. For example, say the route is /publish.
In your view, put something like this:
<input type="button" onclick="window.location = '/publish'">
The value of the onclick attribute must be valid JavaScript, which will be executed when the button is clicked. In JS, setting window.location causes the browser to navigate to a different page. In this case, we are making the browser navigate to /publish, which will cause your publish action to be invoked. Whatever you render in publish will then appear in the browser.
In the code for publish which you show above, your Ruby syntax is wrong, but I am assuming that it is just a sample, not the actual code which you are using.
Your ruby on rails code is server side.
The code in your view e.g <input type="button" onclick="<% controller.publish %>">
is client side.
You can't call server side methods directly from client side code, since the client code is just running in the user's browser.
I've not used RoR so don't know the details but you will have to submit a message to the server from the client side code, at the server side you will then want to receive this and call the publish method from there.
Hope this helps.
First, if your SQL statements are going to change any data (which it looks like they are meant to), it's important that you use a POST request and not a GET request. To do that, you either need to use a basic form submission instead of clicking on a link, OR use javascript to submit the POST request when clicking on the link. Let's talk about the second way since that will stay consistent with how you want the app to look.
Assuming jQuery, you can use the jQuery.post method to post to your publish action when the button is clicked. In the success callback, you can display the message about the sql statements having been executed.
#alex-d's answer seems to be enough. Just use button_to and at the end of your publish action you can redirect to the same page (or the same action as before, if you're loading records to show in the view).
EDIT: From #alex-d's answer:
Create a route which will invoke publish when requested. For example, say the route is /publish.
GET '/publish' to: 'Controller#publish'
In your view, put something like this:
<input type="button" onclick="window.location = '/publish'">
Now on your controller method, redirect:
def publish
do execute sql statements
flash[:notice] = 'sql statements executed.'
redirect_to route_where_the_button_view_is_path #(or render if that controller method isnt necessary)
return #to avoid multiple render or redirect error (maybe not necessary)
end
PD: My code may not work at the first try, I'm working this out from memory.
GL & HF.

In a Rails app, how can I make a link load in a div as opposed to refreshing the whole page?

I'm still a beginner at web development. It's not my profession. So go easy.
I started building a rails app today, and realized it would make my application so much better if I could get certain links to display in a separate div instead of a new page, or refreshing the entire page. I'm not quite sure how to search for this, and I keep chasing red herrings with google.
Basically, I have a list in a div on the left side of the page, and when one item from that list is clicked, it should appear in the right div. (Nothing else on the page need be changed)
That's really as simple as it is. Do I need to use Javascript for this? Can I get away with the rails js defaults, or should I be using JQuery?
Is there a way to do this without javascript? I really just need a push in the right direction here, I'm tired of not even knowing how to search for this, or what documentation I should be reading.
Like I said, go easy, and you should just go ahead and err to the side of caution, and assume I know nothing. Seriously. :)
Thanks in advance,
-Kevin
(By the way, I'm developing with Rails 3)
Create your views (along with controllers) to be shown inside the div for each item on the left menu. Lets say we have the following structure now:
Item1 (Clicking on it will fetch:
http://myapp.com/item1)
Item2 (Clicking on it will fetch:
http://myapp.com/item2)
and so on...
make sure you only render the html to be put inside your content div. Should not include <head> <body> etc. tags
In your main page you may have your markup like this >
<div id="leftMenu">
Item 1
Item 2
</div>
<div id="content">
Please click on an item on the left menu to load content here
</div>
Finally, add the following Javascript (you'll need jQuery; trust me it's a good decision).
$("#leftMenu a").click(function () {
$("#content").load($(this).attr("href")); //load html from the url and put it in the #content element
return false; //prevent the default href action
});
You will need JavaScript if you want to avoid reloading the page. You can use link_to for links in your lists, and you'll need to use :remote => true to make it send AJAX requests to the server. The server will need to respond appropriately and supply HTML for your div.
link_to documentation is here: http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to (and admittedly it isn't very useful for AJAX functionality).
The last post in this thread shows one possible solution you could use.

RoR- How to use div onclick to render results in a separate area of the page?

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

can link_to lead to rendering sth?

i want to render a partial within a view. so that when button MORE is clicked everything stays the same just additional characters are shown. in my case the whole article.
<%= #article1.content[0..300] + "..." %>
<%= link_to "more", ....... %>
i dont know what the right methot would be. somehow i have to explain to rails that when button more is clicked it shows me the whole article. maybe i shouldn't use method link_to ..
thank you in advance for your replys
What you're looking for is link_to_remote or link_to_function.
link_to_remote will be fetching the rest of the article from your controller and replacing/appending to a DOM element with a partial via RJS. This allows you to minimize unnecessary data being sent, and facilitates handling users that have javascript disabled.
With link_to_function, the entire article will be served when the page is loaded, but the everything beyond the first 300 characters will be hidden by CSS. This is easier to set up but sends a lot more data, it also relies on the user having javascript enabled.
Without looking at the source the average user probably couldn't distinguish between the two methods.
Which choice you go with is up to you. Sorry, I haven't got time to provide code examples, but the internet is full of them.
try link_to_function, use truncate for part and insert hidden tag with full text, switch them using javascript in link_to_function

Resources