Rails inserting javascript as a flash notice or message? - ruby-on-rails

I'm wondering if this is a good idea or not, either way I'd like you guys opinion on how to best achieve this sort of messaging popup system I have in my app.
Under some occasions I want to popup a lightbox for users when certain actions are triggered. I already have the lightbox working and opening when when my controller returns JS for a request.
Here is the senario, I want to check if a user has new messages when a new request is made, and if they do I want to show the messages in my lightbox when the new page is loaded.
Should I just put some JS at the bottom of my <body> and render it if the user has messages? Or should I use like flash[:notice] and have it render as JS or something... I'm a bit stuck you see.

Don't use flash notices, this is not what they are for at all. I would have something in the layout like this:
<% if (messages = current_user.new_messages).size > 0 %>
<%= javascript_tag "display_messages(#{messages.collect(&:message_text).inspect})" %>
<% end %>
obviously here i'm guessing at your messages' methods but you get the idea. .inspect will give it an array of strings, you could give it the message data as a json object or whatever.

Related

Display selection of index in a partial

I've been trying to solve the following challenge all day without any luck.
When going through forum posts I came across jQuery and AJAX which are both new concepts to me and which I'd rather skip for now, if possible.
I've got a partial, "navbar-left", which shows a list of all bank accounts in my model Account.
When the user clicks on one of the items in the list, all transactions of that account should be shown in the same page at the right. The partial below links to a new page which is not how I'd like it.
The navbar-partial:
<ul class="nav nav-pills nav-stacked">
<% #accounts.each do |account| %>
<li role="presentation"><%= link_to account.account_holder, account_mutations_path(account.id) %></li>
<% end %>
</ul>
Any tips on how to get this fixed is much appreciated!
The page with the navbar at the left
The mutations in a separate page instead of a partial
Either you're sending viewers to a new page, or dynamically loading content within their current page.
If the latter, then the only solution is AJAX.
Luckily, Ruby on Rails makes transitioning from one to the other very easy.
Here is a gist of how it works:
<%= link_to account.account_holder, account_mutations_path(account.id), remote: true %>
This was pointing back to some page previously (e.g. action.html.erb).
Because of remote: true, it's going to be sending JS directly to the browser instead of a new HTML page (e.g. action.js.erb in the same view folder and same action name).
Here we can control the behavior we want by rendering a partial using ERB and using JS to change the HTML content of some part of the page:
// action.js.erb
$('#some_element').html('<%= j render "partial" %>')
Which will insert the HTML of the partial directly into the JQuery that changes the content dynamically.
Where j is a shorthand for escape_javascript.
Without escaping, the Ruby output is interpreted as file output and newlines would break your JS.
Example JS output without escaping:
// Bad
$('#some_element').html('<span>Content</span>
<span>More Content</span>')
Example with escaping:
// Good
$('#some_element').html('<span>Content</span>\n<span>More Content</span>')
http://guides.rubyonrails.org/working_with_javascript_in_rails.html
https://launchschool.com/blog/the-detailed-guide-on-how-ajax-works-with-ruby-on-rails
There are more great examples online and even Railscasts.
Really AJAX is the best way to do this, and it's not as complicated as you might think. But if you really want to skip AJAX then your best approach is probably to load ALL transactions for all accounts, in different div's and then show or hide them based on which is clicked.
For a rudimentary introduction to this look at javascript tabs... you click on a tab, the appropriate information is shown.
http://www.w3schools.com/howto/howto_js_tabs.asp
You can do this very simply without ajax. The big difference would be - it's not the same page. One page would be the account#index (as you have now), the other page is the account#show page.
For the show page, use a very similar view as the index page, the left side would include the partial with one of the account li class="active" to highlight the account you are currently on. For the right side of the page, render the account mutations list items.

Caching DOM changes in rails

I am conducting partial caching which is working really well.
However if I change the DOM inside the cache block those changes arn't cached. Is there a way to also include those changes?
Here is what I have so far:
<%
cache(#contact.hash_key) do
%><div id="<%=#contact.hash_key%>"></div><%
end
%>
<script>
//use ajax to prepend new messages.
$(document).ready(function(){
$.get("/messages?cid=<%=#contact.hash_key%>", function(data) {
$("#<%=#contact.hash_key%>").prepend(data);
});
});
</script>
UPDATE
Ok so I am trying to attempt to cache the result before it enters the DOM with the same cache key. That way when the cache block is rendered the new data is included with that key.
But I'm not sure the correct way to structure this.
Done!
So for anyone wanting to do the same thing here is a brief outline on how to do it. You may need to make changes or tweak this solution to fit your own.
This will only work if you are using cache keys. In my instance I have 2 types. A contact.hash_key and a message.hash_key
All message caches are kept inside a parent contact cache. So essentially:
<div id='contact-hash'>
<div id='message-hash-1'>
<div id='message-hash-2'>
<div id='message-hash-3'>
First of all we need to loop through the messages and see if they are cached. If they are then you can just render the cached copy. You can do this by using the Rails.cache.read method:
messages.each do |message|
cache = Rails.cache.read 'views/'+message.hash_key
if cache.nil? == false
%><%= cache.html_safe %><%
end
end
So now we have a list of messages from cache thats already been loaded. So what about new messages? Lets load these via ajax so the user isn't waiting for a boring page load.
You will notice in my question above I have querying "/messages?cid=<%=#contact.hash_key%>" in my AJAX call. This is calling the messages controller and rendering the index view.
Before we want to load the rendered view into the DOM we want to write it to the cache first with, surprise surprise, the identical message.hash_key we are going to use to read it.
So in your view:
<%
cache(message[:hash_key]) do
%>
<div class='message'>
This is a new message from the server.
</div>
<%
end
%>
If in some situations this doesn't work (god knows theres so many app permutations out there) you can also use Rails.cache.write 'foo', 'bar' in the controller instead of caching it at the view level.
And there you have it. Now you can add the new hash_key to the list and then render the view back to the DOM as the results of your AJAX call.
Now with the new hash_key in the list you can loop over it and it will come up as a cached copy.
This may or may not be the most elegant solution. If someone wants to simplify or give any advice on it so I can improve it that would be much appreciated.

Displaying flash message in portion of page that is otherwise not updated

I'm looking to display my flash messages in a portion of the page that is otherwise not always in a partial that gets updated.
In other words, I may submit a form that updates a partial via ajax. But I want to display the flash message in a portion of the page that is outside of that partial.
I could have some javascript in every single necessary js.erb file to update the flash partial, but that seems crazy. Is there a more simple way of going about this?
I don't have to necessarily use flash messages either if something custom would work better.
Thanks!
You can do it the low-tech way by using a :remote call on your form that, when executed, will inject some HTML back into your page from a partial of your choosing.
It's pretty easy to do in a .rjs view:
page['flash'].html(render(:partial => 'flash'))
You can also do it in a .js.erb view using jQuery:
$('#flash').html("<%= escape_javascript(render(:partial => 'flash')) %>");
I tend to think the .js.erb method is a lot more ugly, but we all have our preferences.

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