Sending changing params through periodically_call_remote - ruby-on-rails

I'm using periodically_call_remote to update a portion of a page that contains a list of objects. I send along with the url a param containing the created_at date for the most recent object in the database. The action that is called then get all the objects that have been created since then and renders a partial which displays them at the top of the list.
The problem is that I can't seem to figure out how to make it so that the next time periodically_call_remote triggers it sends along the created_at date for the new most recent object (if there is one). I tried putting the periodically_call_remote inside the partial that is being rendered but that caused all sorts of problems (This explains why you shouldn't do that).
Is there some way I can make periodically_call_remote send along a new param each time it's called? As it stands right now it just sends the same one over and over which means that new objects get rendered more than once.

Hackery you say? :)
Store the parameter in a hidden div. You can access the contents of that div via Javascript, which periodically_call_remote will accept as part of the :with option.
When the parameter changes, simply update the contents of the hidden div as part of your controller action.
So, for example..
<div id="date_to_check_from" style="display:none;"><%= #initial_created_at %></div>
<%= periodically_call_remote :url => path_to_controller(#normal_params), :with => "'date_to_check_from=' + $('#date_to_check_from').html()", :method => :get, :frequency => 10 %>
That will get you params[:date_to_check_from] in your controller. Then update however you want, e.g.,
render :update do |page|
page << "$('#date_to_check_from').html('#{#new_date_to_check_from}');
end

It's possible to do some hackery, but I recommend that you start looking into writing your own JavaScript code to perform AJAX requests. Rails' helpers like periodically_call_remote aren't meant to be used in such complex situations.

Related

Rails update instance variable on ajax call to a method from the same controller

I have a view that is handled by a simple controller:
class CountController < ApplicationController
def count
#index = 0
end
end
In my view I just added a button:
<%= link_to "Change next day", increase_count_path(#index), :class => 'btn' :remote => true %>
The request is being handled by a method I added in the CountController:
def increase_count
#index = params[:index].to_i + 1
end
After trying it, I saw that each time the request is being sent to /increase_count/0 , so this obviously doesn't update the variable as I'd like it to.
So my guess is, the 2 are not linked. The first one has its scope in the view, and the second one, from the increase_count method is visible in whatever javascript I would render from it.
How can I achieve this in Rails? The thing I was trying to achieve and ran into this was the following (simplified version): I have an array of 3 Strings. Firstly I display the first one. On click I would like to make an Ajax call, increment the index, and display the next string. But I ended up showing only the second one, because the next calls don't update the index.
Your AJAX call will indeed update the #index instance variable within the controller, however if you don't re-render the link then it will continue to use the initial value of #index.
Consider re-rendering the link within a JavaScript template.
E.g.
// inside increase_count.js.erb
// Fetch the link in question and re-render it
// The newly rendered link will use the updated value from the instance variable within the #increase_count action
// Generates the link
// Use the j helper to escape any JavaScript within the text
var link = "<%= j link_to("Change next day", increase_count_path(#index), :class => 'btn' :remote => true) %>";
// Select the link using jQuery and update it
$("...").html(link);
You may want to turn the link into a partial to avoid duplicating the code in the view and in the JS template. You'll also want to use a good selector to grab the link more easily.

Rails: What does it actually mean to "render a template"

I've become a bit confused about the idea of "rendering" a "template" due to the way an author speaks about it in a book I'm reading.
My original understanding of "rendering a template" was that it meant that Rails is providing the content that is viewed on the screen/presented to the viewer (in the way that a partial is rendered) but the book I'm reading seems to be using the concept of "rendering a template" to also mean something else. Let me explain in context
This book (rails 3 in action) sets up a page layout using the conventional layouts/application.html.erb file, and then it "yields" to different view pages, such as views/tickets/show.html.erb which adds more content to the screen. that's all straightforward..
Within this view views/tickets/show.html.erb, there is a rendering of a partial (which is also a straightforward concept).
<div id='tags'><%= render #ticket.tags %></div>
Now within this partial there is, using ajax, a call to a "remove" method in the "tags_controller.rb" which is designed to allow authorized users to remove a "tag" from a "ticket" in our mock project management application.
<% if can?(:tag, #ticket.project) || current_user.admin? %>
<%= link_to "x", remove_ticket_tag_path(#ticket, tag),
:remote => true,
:method => :delete,
:html => { :id => "delete-#{tag.name.parameterize}" } %>
<% end %>
Now here is the "remove" action in the tags controller (which disassociates the tag from the ticket in the database)...
def remove
#ticket = Ticket.find(params[:ticket_id])
if can?(:tag, #ticket.project) || current_user.admin?
#tag = Tag.find(params[:id])
#ticket.tags -= [#tag]
#ticket.save
end
end
end
At the end of this remove action, the author originally included render :nothing => true , but then he revised the action because, as he says, "you’re going to get it to render a template." Here's where I get confused
The template that he gets this action to render is "remove.js.erb", which only has one line of jquery inside it, whose purpose is to remove the "tag" from the page (i.e. the tag that the user sees on the screen) now that it has been disassociated from the ticket in the database.
$('#tag-<%= #tag.name.parameterize %>').remove();
When I read "rendering a template" I expect the application to be inserting content into the page, but the template rendered by the "remove" action in the controller only calls a jquery function that removes one element from the page.
If a "template" is "rendered", I'm expecting another template to be removed (in order to make room for the new template), or I'm expecting content to be "rendered" in the way that a partial is rendered. Can you clarify what is actually happening when a "template" is "rendered" in the situation with the jquery in this question? Is it actually putting a new page in front of the user (I expected some sort of physical page to be rendered)
You're nearly there! Rendering a template is indeed always about producing content, but for a slightly wider description of content. It could be a chunk of html, for example an ajax call to get new items might produce some html describing the new items, but it doesn't have to be.
A template might produce javascript as it does in your second example. Personally I am trying to avoid this and instead pass JSON back to the client and let the client side js perform the required work.
Another type of rendering you might perform is to produce some JSON. APIs will often do this, but you might also do this on a normal page. For example rather than rendering some javascript to delete tag x you might render the json
{ to_delete: "tag-123"}
and then have your jQuery success callback use that payload to know which element to remove from the DOM, by having this in your application.js file
$('a.delete_tag').live('ajax:success', function(data){
var selector = '#' + data.to_delete;
$(selector).remove()
}
(Assuming that your delete links had the class 'delete_tag')
Rendering JSON like this isn't really a template at all, since you'd usually do this via
render :json => {:to_delete => "tag-#{#tag.name.parameterize}"}
although I suppose you could use an erb template for this (I can't imagine why though).
My understanding is that js.erb is "rendered" by executing the javascript functions within it. Very often something like the below is done:
jQuery(document).ready(function() {
jQuery('#element').html('<%= escape_javascript(render pages/content) %>');
});
There's a really succinct overview of rendering at http://guides.rubyonrails.org/layouts_and_rendering.html that may help as it also goes into the details of the ActionController::Base#render method and what happens behind the scenes when you use render :nothing (for example). Render but can be used for files or inline code as well -- not just 'templates' in the traditional sense.

How to do user content from CMS in Rails

I'm trying to build a CMS in Rails from scratch, and for showing the user generated pages I'm having trouble deciding exactly how to do it.
The way I have it right now, I have a controller named 'content' with a single action called 'show'. In routes.rb I have a rule that passes any name after the name of the website to the content controller, show action with parameter name.
For example, www.mysite.com/about_us would route to
:controller => 'content', :action => 'show', :page => 'about_us'
Inside the content controller, I do a find on the Pages model to locate the named page:
#markup = Page.find_by_name(params[:page])
And then in the show.html.erb view I use the raw helper to display the content:
<%= raw #markup.text %>
Does this method violate anything about the way I should do be doing things in Rails? Or is this an OK solution?
I ended up using the sanitize helper, by default it removes <script> tags which is essentially what you need to prevent XSS, as far as I understand. For those who have found this via a search, the only code that changes from what I described above is that in the view you change to:
<%= sanitize #markup.text %>

Posting a form through popup in Rails

I have a model called Details, and two controller methods new and create. New method displays a form to create Details (in new.html.erb), which gets posted to the Create method that saves it. (when it succesffully saves, it it renders the new.html.erb file with the details.) This works as expected.
Now i want a separate page with a link to fill in these details. I want the click to do the intended work through a popup, example redbox. When you click on that link, a popup should show the form, whose submit should post the form, and if it is successfully done, then refresh the original page. If the post is unsaved, then the same form should show the errors. What do i need to do to make it work in Ror? I guess i need some stuff to go in new.js.rjs and maybe create.js.rjs, but i can't really figure out what to put in those files.
Redbox updates the page's dom to add a div at the end of it. So your form is a part of the main page.
So if you add a form tag in this redbox, all your page will be reloaded as there's only one.
So you add anywhere in your page (preferably at the end) :
<div id="redbox" style="display: none;">
<%= form_for #details do %>
# Whatever form fields you want here
<% end -%>
</div>
You do a link that'll open the redbox :
<%= link_to_redbox 'Open The Details Form', 'redbox' %>
This will display your redbox with your form.
And as it is the same page, not a new windows, when you'll validate your form, it'll reload the all of it.
I used a link_to_remote_redbox for this, which on clicking, fetches the form rendered by the new method call in a popup widnow. it submits to the create function and it is now working. actually i had previously made it work without ajax and i was having difficulty in making it work with ajax. the problem was solved once i made separate partials for ajax calls, and doing:
respond_to do |format|
format.js { render :template => 'detail/ajax_template'}
...
end
I provided different templates for both create and new method calls, used the :html => {:id => 'some-id'} in form and the :update => {:some-id} to replace the form with the message that it worked correctly.
So I didnt know that i needed separate templates for the different styles of forms, and that i needed to use the :update option to replace the form when i asked the above question.

Attaching onClick event to Rails's link_to_function

How do I attach an onclick event to a link_to_function such that clicking on the event refreshes an element on the page (using partials)?
When the user clicks the generated link, I'd like to refresh the partial containing the code so that i gets updated.
def add_step_link(form_builder)
logger.info 'ADD_STEP_LINK'
link_to_function 'add a step' do |page|
form_builder.fields_for :steps, Step.new, :child_index => 'NEW_RECORD' do |f|
logger.info 'inserted js'
html = render(:partial => 'step', :locals => { :step_form => f, :i=>#i+=1})
page << "$('steps').insert({ bottom: '#{escape_javascript(html)}'.replace(/NEW_RECORD/g, new Date().getTime()) });"
end
end
end
I have a partial in a larger form that contains just:
<%= add_step_link(technique_form) %>
I am attempting keeping track of the number of steps in a technique. In the form I am creating, users can add new steps to a set of instructions. Right now, I have default fields for steps 1-7. Adding one step, gets you step 8. The problem is that subsequent steps are numbered '8' also.
I am extending the "Multiple child models in a dynamic form" tutorial in http://railsforum.com/viewtopic.php?id=28447 for my own purposes.
Ok, I'm a little confused about what you are doing, but I'm going to try and make some suggestions.
Rather than use link_to_function, use link_to_remote. Link to function calls javascript, but what you actually want to do is call back to a controller that then runs some rjs to either replace the full partial or, more likely, append the new partial (containing the step) to the end of your current steps.
This is similar to all those examples you will have seen where people append a comment to the end of their blog comments (expect using link_to_remote rather than remote_form_for) see 3/4 of the way through http://media.rubyonrails.org/video/rails_blog_2.mov
You can see the docs for link_to_remote here: http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html
I suggest using link_to_remote as RichH suggests. The trick for you it seems is keeping track of #i. I'd either put it as a URL parameter in link_to_remote, or in the session object. I'd suggest the session—it seems easier.

Resources