How to append ruby code to html element - javascript

I'm making a chat using ActionController::live.
stream in my ChatsController pushes posts.
def stream
response.headers['Content-Type'] = 'text/event-stream'
start = Time.zone.now
loop do
Post.where('created_at > ?', start).each do |post|
response.stream.write("event:push\n")
response.stream.write("data:#{post.to_json}\n\n")
start = post.created_at
end
sleep 2
end
rescue IOError
ensure
response.stream.close
end
Using javascript, I wrap gravatar and this json with <li> and append this to <ul>. Then, I want to use gravatar_for method I defined and render partial for post model.
Would you teach me how to append ruby code (<%...%>) to html elements()? I tried to .append('<%...%>') once, it didn't work.

If your controller is responding to javascript, you can render a partial using from the corresponding js.erb file like so:
$('element').append('<%= escape_javascript(render partial: "post") %>');

Related

Ruby on Rails - modifying part of embedded Ruby in .js.erb

I'm working on a single-page site and have gotten the ajax loading of templates to insert into the content part of the site working. However, I'm having trouble doing this with multiple templates, using a parameter.
I have 5 templates, shared/blog, shared/projects, etc.
In my controller, I'm doing an AJAX call to 'replace'
pages = ['blog', 'projects', 'resume', 'gallery', 'contact']
def replace
#content = params[:content]
if not pages.include? content
content = 'blog'
end
respond_to do |format|
format.js
end
end
In replace.js.erb, I have this code:
$(".content_inner").html("<%= j render(:partial => 'shared/blog') %>");
I have kept it just saying 'shared/blog' because it works for loading the blog if I keep the embedded Ruby static like that. However, I can't figure out how to replace the 'blog' part of 'shared/blog' in here to whatever is in the #content variable. I've tried things like #{content}, but to no avail.
(It does receive the content variable correctly, the issue is just with using it)
Any help would be appreciated!
Thanks.
String interpolation requires double quotes. You're after:
$(".content_inner").html("<%= j render("shared/#{#content}") %>");
A few notes:
The :partial => hasn't been necessary for years in Rails. Just use render <partial_name>.
Rails already comes with a place to store your shared partials: app/views/application. You should move your shared partials there, and then you can render them simply by using render(#content). This is important to how Rails works, because it allows you to override the partial in controller-specific view paths. For example, calling render("blog") will render app/views/<controller_name>/blog.js.erb if it exists, and then fallback to app/views/application/blog.js.erb otherwise.

Rails 4 - event to run code after a partial is rendered

I have a js.erb file that is called with ajax through a controller action. The js.erb file renders a partial. Inside the partial is a data attribute that is generated based from the model. I need a way to run code only after the partial is rendered because the code is using information in the data attribute.
items_controller.rb
def remove_tag
#item = Item.find_by_id(params[:id])
//code to remove tag from item
#item.save
respond_to do |format|
format.js
#item.reload
end
end
remove_tag.js.erb
$("#taglist").html('<%= escape_javascript(render partial: "items/tag_list", locals: {item: #item}) %>');
//the code below needs to be run after the above partial is rendered
$('#add-tag').rules("add", {
tagUniqueness: $('#taglist').data('tag-list').split(', ')
});
_tag_list.html.erb
<div id="taglist" data-tag-list="<%= item.all_tags_list %>">
//more html
</div>
The way it is now, the .rules method is using html data that was there before the partial updates it.
This type of functionality would lend itself to callbacks in javascript/jquery...
A callback function is executed after the current effect is 100% finished.
We used callbacks for executing functions after ajax loads (which had to remain asynchronous). They are highly effective if you can get them to work.
There's a great reference here:
$("#taglist").html('<%= escape_javascript(render partial: "items/tag_list", locals: {item: #item}) %>').promise().done(function(){
$('#add-tag').rules("add", {
tagUniqueness: <%= js #badge.all_tags_list.to_json %>
});
});
To convert hashes or arrays from Ruby to javascript you can use .to_json as JSON basically is a subset of javascript.
$('#add-tag').rules("add", {
tagUniqueness: <%= js #badge.all_tags_list.to_json %>
});

Include a Coffeescript file with ERB in a view

This is giving me a major headache...
So I have an app which requires a sidebar that lists various information to do with a user's player. One section of this sidebar is a friends list. Now, when Player A sends a friend request to Player B, the request should be automatically logged in B's sidebar, and I intend to use WebSockets to do this.
Here is my cp.js.coffe.erb file (there's only a few snippets of ERB at the moment; there will be loads more and I rather get this working first):
$ ->
$("#cp").accordion()
if `"WebSocket" in window`
socket = new WebSocket("ws://localhost:8080")
socket.onopen = =>
console.log("Connection Open")
init = {
sender: "cp"
action: "init"
user: <%= #user.id %>
token: <%= cookies["remember_token"] %>
}
socket.send(init.to_json)
socket.onerror = (e)=>
console.log(e)
socket.onclose = =>
console.log("Closed")
socket.onmessage = (m)=>
console.log("Recieved: #{m.data}")
msg = m.data.JSON.parse
switch msg.action
when "ret_init"
when "friend_udt"
refreshFriend()
refreshFriend() ->
html = "<%= j render 'layouts/friends' %>"
$('#friends').empty()
$('#friends').add(html)
Theoretically, the code itself works fine, the problem being that Rails doesn't let you use ERB in the assets pipeline, and so this file has to sit in app/views/layouts.the file cannot access the variables declared within a controller or use the render method (or most other ERB methods).
Here's the thing: I can't include said file in my application.html.erb file, and I looked into requesting the file with AJAX, but from my understanding that will immediately execute the Javascript once and once only, and I need the methods in this to be constantly available to update the sidebar.
Is there any way of including this file so that it works with the ERB and the CoffeScript so that it would be continuously avaliable to the page? Am I misunderstanding the whole AJAX requesting method?
Thanks #nzifnab for your help with the JS. Now my friends partial looks like this:
<ul id="friendlist">
<% if Relation.find_by(owner: #user.id, type: "freq") != nil %>
<% Relation.find_by(owner: #user.id, type: "freq").each do |r| %>
<li class="friend-request-cp"><%= link_to "/#{User.find(r.character).name}" %></li>
<% end %>
<% end %>
<% if Relation.find_by(owner: #user.id, type: "friend") != nil %>
<% Relation.find_by(owner: #user.id, type: "friend").each do |r| %>
<li class="friend-cp"><%= link_to "/#{User.find(r.character).name}" %></li>
<% end %>
<% end %>
</ul>
I need to apply two different styles to each item, hence why I'm using the ERB here. This works fine, as it's loaded when the page is first navigated to, but my code was supposed to re-render that partial every time a notification comes through of any new interactions. It would then repopulate the list using the data from the database again. Is there a more efficient way of doing this? Can I still do this with the hamlcoffeeassets gem you showed me?
Slight tangent ensues:
By the way, I'm using Ruby 2.0.0-p247 and Rails 4 on Windows 7. I felt the need to include that because of some major compatibility issues with gems that are much different from Ubuntu. I had to move from Ubuntu to Windows because updating from 13.04 to 13.10 broke everything Ruby Gem on that OS. I don't have tome to find a fix: I literally have only four days to get this app built.
You can kinda use erb in the asset pipeline, but you have to remember that it only gets rendered ONCE, EVER, and not once for every user and so even if there was an #user variable (which there won't be), it would never change. You can use erb in your coffee file for things like route paths and environment variables, but not for things like user-specific config and dynamic changes to the JS. It's bad practice anyway.
What you should really do is use a javascript library to read cookies instead of trying to do it with rails (This will give you access to some of the things you appear to be trying to do). And when you need more dynamic behavior you should render data-attributes or other values into the html DOM itself and use the javascript to read that.
Take a look at this cookie library: https://github.com/carhartl/jquery-cookie
There's many others to look at via a quick google search.
socket.onopen = =>
console.log("Connection Open")
init = {
sender: "cp"
action: "init"
user: $.cookie('user_id')
token: $.cookie('remember_token')
}
There are a couple of ways to render new markup for your view using JS. One way is to use js templates. I'm a big fan of the hamlcoffeeassets library here: https://github.com/netzpirat/haml_coffee_assets Although it uses haml for the view, and not ERB. There are ERB variants as well.
You would add some markup to app/assets/templates/friend.jst.hamlc like so:
%p This is my friend markup #{#friend.name}
And then you can render it from your JS like this:
$('#friends').append(JST['templates/friend'](friend: {name: 'Bob'}))
Which will append the markup from your template with the values you've passed interpolated in. In my example you'd end up with this markup inside your #friends container:
<p>This is my friend markup Bob</p>
Alternatively you can render the partial you want via rails into your JSON response as just a string, and then insert that into your document...
So your JS might look something like this:
socket.onmessage = (m)=>
console.log("Recieved: #{m.data}")
msg = m.data.JSON.parse
switch msg.action
when "ret_init"
when "friend_udt"
refreshFriend(msg.friendHTML)
refreshFriend(html) ->
$('#friends').html(html)
UPDATE
In reference to your ERB question... First of all your partial is incredibly inefficient making similar calls to the database four times every time you render it. haml_coffee_assets is for use with the haml markup language (which I prefer over ERB), if you want ERB then use eco instead: https://github.com/sstephenson/eco
If you want to render this in the JS, then you need to send this "friend relation" data as JSON through the notification data response, you do not have access to active record OR any controller methods or instance variables when rendering javascript partials - they don't hit back to the server, they only use what is accessible by your javascript at the time.
This should really go to app/assets/javascripts/cp.js.coffee.erb, you can use erb in the asset pipeline just fine (see here) Make sure you are spelling the coffee extension right, though!
Doing this, you should be able to call this via ajax without problems, the path would be /assets/cp.js.
try this gem: 'coffeebeans'
name your coffee file as "some_file.html.erb"
<%= coffeescript_tag_do %>
# your coffee script here ...
<% end %>
in another erb file:
<%= render file: '.../some_file' %>

Can server side loop be done in javascript/ajax?

How can I loop server side code on the client without javascript? I have this loop in my rails app
//partial = _manufacturers
<div id="all_manufcaturers">
<% for manufacturers in #manufacturerss%>
ID: <%= h manufacturers.id %>
<% end %>
</div>
How can I render this using ajax? I know something like the following works since it is just a static replacement:
$("#manufacturers_count").html('Manufacturer - <%= #car.manufacturers.count %>');
But pseudocode like this does not work since the partial contains a loop:
$("#all_manufacturers").html('...render(manufacturers)...');
Yes, it can be done. You will want to make a server side script (e.g php) that builds a dataset for you and echos it with json_encode. You will then want to parse the response from the request with the appropriate javascript decode function in whatever library you're using (example, jQuery.decodeJSON()). You can then loop through the response set and render.

Rails Javascript parsing using array from Controller

I am doing Ajax Call from View, then controller is fetching data from DB into an Array, now this array value I want to pass to JavaScript, so that I can update data in a table with different id's
Controller code:
def AjaxView
#var1 = Var.find(:all,:conditions => { :varname=> "one" },:select=> (params[:col]))
respond_to do |format|
format.js
end
end
AjaxView.js.erb code:
$(document).ready(function() {
$("#test").text("valuetoupdate");
});
Now when I run this code it successfully update "valuetoupdate" at id =test in view page.
Instead of this I want to update all values one by one from array #var1.
I searched more and realized that array #var1 generated in Controller will automatically get transferred to AjaxView.js.erb file. Now I have to iterate over all values, but this code doesn't work in JavaScript file:
<% for var in #var1 %>
$("#3").text(var);
<% end %>
it gives blank response
Thanks Guys,
I am able to resolve my issue, in following manner,
I moved away from for loop implementation, instead start using if else condition,
<% if #var.to_s == 'valuetoupdate' %>
{ }
<% elsif #var.to_s == 'valuetoupdate1' %>
{}
And it worked fine for me.

Categories

Resources