Is it right to have files that mix Javascript and ruby? i.e. (.js.erb)?

I recently read that implementing Ruby inside JavaScript is not a good idea. However, books like David Heinemeier Hansson Agile Web Development with Rails are exactly what he does. If embedding ruby ​​with JS is NOT a good idea, then what is best for this case? Given something simple: (jQuery + ruby)

posts_controller

def create @post = Post.new(params[:post]) respond_to do |format| if @post.save format.html { redirect_to(@post, :notice => 'Post was successfully created.') } format.js #will use this response to process ajax else format.html { render :action => "new" } end end end 

create.js.erb

 $tr = $('<tr>'); $td1 = $('<td>').text('<%= @post.title %>'); $td2 = $('<td>').text('<%= @post.content %>'); $tr.append($td1, $td2); $('table tbody').append($tr); 

How should I reorganize to follow the “best practice” of not embedding ruby ​​with JS? (if it is true)

Do I really need to be enlightened on this, and maybe the concepts are correctly understood, because I read that 3.1 rails completely separate JS from Ruby through assets? (It is right?)

Thanks!

+6
source share
3 answers

RJS templates were, in fact, the same as it has been done for a long time, so you still see such a prevalence of technology in textbooks. At the same time, as you noticed, they are on the way to work and not without reason.

I am sure there are many reasons why RJS templates are very bad things , but the big question is how much do they connect your JS look to your HTML representation. Because of this, many problems arise, some of which are:

  • Lack of flexibility.

    Using your bit of code as an example. What if you want to be able to create messages from a different view? And have a different effect? Maybe there is no <table> on the page and you just want to display a success message? Etc.

    What if you just need a view of the data about your posts, but your javascript templates were written to control HTML?

    How do you deal with all this in one create.js.erb , which is closely related to the new.html.erb posts new.html.erb , most likely

  • Complexity.

    RJS templates work in a vacuum. Generated on the server side, their execution is not related to DOM events. This makes it difficult to do things like, say, update the <form> on the page after creating the object, since you don’t have a framework to select the appropriate <form> in the JS template (for example, <form id="new_post_123"> ), There are workarounds, but they are more complicated than they should be.

    When binding to the form to the client side and working with the result, this problem is eliminated. You do not need to search for the necessary form for updating after the answer.

    With RJS, you don’t have such a binding, and you are forced to use the well-known HTML structure to extract and manage the relevant elements. One example of unnecessary complexity.


Regarding your question:

Do I really need to be enlightened on this, and maybe the concepts are correctly understood, because I read that 3.1 rails completely separate JS from Ruby through assets? (It is right?)

This is essentially true. A consortium of assets, while cool, offers nothing new. Asset frameworks such as Sprockets and Sass, and the workflows they allow, have been around for some time. The Rails 3.1 asset pipeline simply introduces them into standard practice. This is more of a perspective issue, as DHH talked about in his recent RailsConf keyword . Attracting a large organization to these assets, in particular js files, it makes them feel more like first-class citizens, so to speak, deserving the same attention as your internal code. Unlike the feeling of an "unwanted drawer" public/javascripts .


Regarding the implementation:

You can do something like this (although it is unverified and slightly simplified, for example, in Rails 3 you can use respondents for this, and not for the response_to block:

 # as you have, but returning the object as data which can be handled client-side, # rather than RJS generated by the server def create @post = Post.new(params[:post]) respond_to do |format| if @post.save format.js { render :json => @post } else # ... end end end // Then in your client side JS, a handler for your remote form. $(function(){ $('#your-create-form').bind('ajax:success', function(data, status, xhr) { // simply repeating what you had in the template, replacing the erb with // attributes from the returned json $tr = $('<tr>'); $td1 = $('<td>').text(data.title); $td2 = $('<td>').text(data.content); $tr.append($td1, $td2); $('table tbody').append($tr); }); } 
+9
source

If you paste dynamic data into JavaScript files, you often have to specify caching rules that are appropriate for content that can change frequently.

If you need to process dynamic content using JS, then it is usually best to have a static, cached, reusable script that receives data from other sources.

In this specific example, although I'm not sure, since there is not much context, it seems that you are better off creating HTML directly, instead of generating JS, which generates HTML.

+5
source

I am sure that you can find this question asked by beginner PHP developers, Perl, ASP and any other server languages ​​there. There do not seem to be too many cases where you want your javascript code to be embedded .. the only one that might be that you configure it in a specific situation, but from my point of view I can’t think of any situations, when you need to configure it that way.

Accordingly, if you have a lot of javascript, and you include all this in your output, you will inflate your page. Page 1k will turn into a page> 100k Pages if you add a large application. And along with this, it will most likely be more difficult to cache this information, since you will probably configure the output a little if the user is logged in, or if there is a special announcement that day, etc. You are much better off decoupling it from your own file so that you can "minimize" it ( http://en.wikipedia.org/wiki/Minification_%28programming%29 ).

From developer to developer, I can tell you terrible stories about how javascript (and html) is embedded in PHP and Smarty templates. Be nice to whoever you work with and do not split all the languages ​​into your own files. Let's say you work with Bob, and he's a great guy, but knows nothing about the application and how he spills out his code. If the javascript that will look like in erb is disappointing due to the lack of a single truth point for the application - if it wants to change something, it will look through all your erb to find out exactly where it should put it or where it was originally from . And do you really want someone who knows little about your backend structure to dig into these files?

There are several cases where you want to put boot data. If you have a lot of data to enter the page at startup, then when assigning several variables at page startup, it is more efficient than exiting and executing an ajax request every time the page loads.

Please be kind to us guys, and if you have no good reason, keep JS in separate files :)

Edit: here is an example of what you want (I think), without using template javascript:

app.js:

 postUpdater = function (data) { $tr = $('<tr>'); $td1 = $('<td>').text(data.title); $td2 = $('<td>').text(data.content); $tr.append($td1, $td2); $('table tbody').append($tr); }; $("#save_button").click(function () { $.post('/save/ur/', {the:data}, postUpdater); }); 

In ruby, you just need to render @post for json. I think this is literally @ post.to_json, but you might need require 'json' to make it work. It may lead you there faster, but: output formated json with rails 3 (I'm not really a ruby ​​guy .. we just use him in the company I work for, of course, I picked him up)

Now, regarding the theoretical question of why not just release a javascript template file. Let's say you have a whole bunch of things that should happen when you save this javascript file. This means that you have to output a lot of things on this ajax request and execute it. You will be pushing a larger file over the Internet (a bit slower) and you may have the “eval” response (eval is evil). So this is one bad thing. Another, perhaps badly, is that you lose access to where you called this salvation. So, if I have this opinion ..

 new PostViewer({ savePost: function () { var self = this; $.post('/save/url/', {the:data}, function (response) { self.trigger('saveSuccessful', response); }); } }); 

When you call savePost it will be more difficult (without the possibility of introducing numerous hacks) just to tell the opinion "Hey, the rescue was successful!"

Hope a little more for the purpose for what you were looking for.

+4
source

Source: https://habr.com/ru/post/896079/


All Articles