Backbone With Rails - ruby-on-rails

I'm getting my data from a service and then setting the data to my bean object and want to using the same data in my view displaying it in a form in rails view now. Now I want to validate this form using backbone.
I'm new to both Rails and Backbone.
Kindly give me an idea on how to proceed on this.

I think perhaps you are confused about how web applications work. Backbone is a client-side framework; it uses Javascript code that is run in your users' browsers. Rails is a server-side framework; it uses Ruby code that runs on your server.
Given all that, your Backbone code and your Rails code by definition have to be completely separate. The two can communicate in only two ways:
1) Your Rails code can write <script> tags to the page (inside a .html.erb file) and put variable data there; for instance:
<script>
var myVarFromRails = '<%= someRailsVariable %>';
</script>
When that comes back from the server (ie. when you view source the page) that will get converted to:
<script>
var myVarFromRails = 'foo';
</script>
(assuming 'foo' was the value of someRailsVariable).
2) Your Javacript code can make AJAX requests to Rails URLs, and whatever the Rails code spits out there will come back as the response to your AJAX request. In other words you can do:
$.ajax({url: someRailsUrl, complete: function(response) {
// whatever the server sent back will be inside the "response" variable
}});
Other than that the two are pretty much entirely separate, and if you want to do the same thing in both of them (eg. validate a form) you essentially have to write the code twice, once for Ruby and once for Javascript.
I say "essentially" because there are Rails plug-ins which do #1 and #2 for you in different ways. I'm not a Rails expert, and even if I was there are so many of these plug-ins that you really need to look for yourself to find out what exists and what makes sense for your codebase.
Hope that helps.
* EDIT *
I know I just said I wouldn't list libraries, but then I realized it'd be more helpful if I at least provided a few to get you started. Just don't take these as canon; they're simply some popular libraries at the moment, but they may or may not be right for you.
https://github.com/codebrew/backbone-rails
https://github.com/meleyal/backbone-on-rails
https://github.com/aflatter/backbone-rails
https://learn.thoughtbot.com/products/1-backbone-js-on-rails
http://kiranb.scripts.mit.edu/backbone-slides/
That last two aren't actually libraries, they're a book/presentation, but I thought they might be useful.

Related

Angularjs Light version

I use angular in many projects, specially in ASP.NET MVC, but i dont like angular-
router (also ui-router, this is not much problem indeed as it's just a plugin) - concept of web-apps kills all ASP.NET features
services and factories - as all of this can be done inside common controller. (This might sound tricky)
constants and values - as i dont think this is really needed if you use requirejs or other AMD
What i love in angular is just directives, and when i make big nested directive, i use same controller foreach, so there is no $scope interacting (less watchers)
.controller('BaseGridCtrl', function(){
//instead of
//$scope.value = 123;
var ctrl = this;
//this is for Table-base-directive
ctrl.value = 123;
//this is for Table-head-directive
ctrl.value2 = 123;
});
.directive('table-base', function(){
return {
template: '<div>{{bgc.value}}</div>',
controller: 'BaseGridCtrl',
controllerAs: 'bgc'
}
});
.directive('table-head', function(){
return {
template: '<div>{{bgc.value2}}</div>',
controller: 'BaseGridCtrl',
controllerAs: 'bgc'
}
});
.directive('table-foot', function(){
return {
template: '<div>{{bgc.value3}}</div>',
controllerAs: 'bgc',
controller: function(){
var ctrl = this;
ctrl.value3 = 123;
}
}
});
So the link function is used veeery rare. And specially i like that angular easily detects directive - which is great as you just write 1 tag <grid> instead of reactjs components (This also might sound tricky). In my projects i use DotLiquid for razor views (it's stored in database as string) Sample:
<grid theme="some" route="localhost:9000/some/action"></grid>
So dotLiquid just renders this string w/o problem, or even applies other bingings beside angularjs. And this is great as all stuff is self contained. Which cannot be achieved by reactjs - you need to bootstrap components by yourself
React.renderComponent(<Grid />, document.querySelector('#someId'))
resume
Currently it's heavy, about 100kb, but without all this unnecessary stuff it would be really light. I would like to use only directive and controller services, Also with server-side rendering angular gonna bootstrap itself on each request which is not wise, but with lighter version it's a bit tradeoff.
Has anybody tried to strip angular services succesfully? Or is there any consideration, any ideas?
edit
Angular-light looks promising, but:
it doesn't provide HTML tag detection, only attributes
really ugly, alight.directives.al.getValue this looks so bad only for me or someone else?
edit2
Ok, that 100kb might not play alot. But consider it as workout, as you might know, angular start only once, at page load, so it must build the app, pull all modules, configure each, then all services of module, then inject them where they are needed, then supply callbacks from factories and services to any who injects them, at least it gonna check if any exists (on each module), all of this happens at start, only once! By wiping up size, we also can minimize javascript execution(indeed it will), factory and service watchers, so we won't need any parts that aren't used. We can even get rid of controllers (and use them inline), only 1 service. angular.directive (which is best part of party). Have looked at mustache, handlebars, but they are just like reactjs.
You can try Angular Light ~15kb (gzipped), it doesn't have services, factories, constants, values, DI, router and so on.
In addition, it has helpful features like text-directives and a support of Object.observe (benchmark)
edit
It provides HTML tag detection, attributes and comments.
AngularJS is meant for full SPA development. This means that you are not making full round trips to the server all the time. If your application needs to pass data back and forth, utilize the WEB API controllers and pass JSON up to them.
An Asset Management System I am currently working on is full SPA with WEB API and MVC fully wrapped into its needs. User log-in is processed across a full page request everything else is SPA. Additionally, here is something to read more about using MVC/WebAPI and Angular together.
If you are trying to use AngularJS instead of something like BackboneJS then you should be using AngularJS Light which was started for this exact purpose. I haven't used this library specifically, but as it is suppose to be an alternative to libraries I do use. The suggestion, if you want Angular and not BackboneJS or KnockoutJS use AngularJS Light

Why moving the code from html into .js causes issue?

I have asp.net mvc project with knockout.js so my index page is getting really huge because of lots of javascript functionality.
I'd love to move js code into a separate file but it does not allow me to apply it to the most of the code because if I have something like
$.ajax({
url: "#Html.Raw(#Url.Action("Load"))",
Then it pops up a error if I move this part of the code into another file.
Please advise how can I resolve this issue?
Javascript files are not parsed by ASP.net, so the variables you have of #Html.Raw and #Url.Action("Load") will never be processed.
As #James Lai noted, server side code isn't parsed as such by ASP.Net. See this post for a workaround, or you can pick and choose which scripts can still stay on the page (with server-side code) instead of the "everything" - your choice as to which approach meets your requirements.
Javascript files are not parsed by ASP.NET MVC, thus #Html.Raw(#Url.Action("Load")) will not work in javascript file.
Heres workaround
Instead declare a variable in view.cshtml. In script section as
<script type="text/javascript">
var actionUrl = '#Url.Action("Load", "Controller")';
</script>
And use actionUrl in javascript file.

mixing clientside javascript template with rails logic for backbone.js

I've worked a while now with Backbone.js, and one of the things I nowadays run into is; Sometimes you need to have serverside logic into a .eco.jst template
For example
an i18n translation (currently look at i18n.js gem for this)
a path a route without hardcoding it (somemodel_path(somemodel))
authorisation (for example, show a delete button if the user can destroy this model). Atm I solve this by passing in some rights object in the json that gets filled in.
Rendering a html helper like simple_form or S3_file_uploader (atm I solve this with rendering it serverside, and put the display on none)
As you know, .eco get parsed by node.js, so I can't call ruby in the eco files. Most of these problems I solve by basicly creating a "data" object in the head. Similar to this:
window.data = {
some_translation = "<%= t('cool') %>",
<%= "can_destoy_model = true," if can?('destroy', Model) %>
post_edit_link = "<%= post_path(#post) %>
}
Besides this being bulky (this is just an example, normally this would be more ordened or I add a html5 data attribute to some dom element), It's time consuming, sometimes you have to recreate complete business logic which otherwise would be a oneliner in rails (take for example the S3_file_uploader, which requires encoded amazon policyfile and a token)
What are your thoughts about this? Should I perhaps not use .eco (although I like templates in seperate files instead of poluting the view). Would I able to use serverside logic if I for instance used mustache or handlebars and which gem would you recommend if so?
My experience with Backbone.js is kind of limited, but I've managed to setup an environment with logic-less templates using the following gems:
handlebars_assets
haml_assets
And a bunch of other stuff, even a mini-framework I'm currently working on (you can find it here)
I picked this approach for building Single Page Applications using Backbone.
Basically, the haml_assets gem provides sprockets with the ability to parse .haml files, this is not needed but I love HAML syntax. The handlebars_assets gem provides means to parse Handlebars templates, both on the server-side and the client-side. You can use Ruby code inside the templates and you would solve both the i18n and the path methods problems you mentioned.
I've found these tools to be excellent to help DRY an application's templates, and it can really save you from adding logic inside templates. If you use Backbone Views to take, for example, decisions on whether to show a delete button or not, you can keep the logic inside the Backbone View, and use that logic to render the proper Handlebars template (or partial).
Using your example:
Coffeescript:
class ProjectShowView extends Backbone.View
template: (context) -> HandlebarsTemplates['projects/show'](context)
deleteButtonTemplate: (context) -> HandlebarsTemplates['projects/shared/delete_button'](context)
render: (canDelete = false) ->
#$el.html(#template(#model.toJSON()))
#$('.delete_button_container').append(#deleteButtonTemplate()) if canDelete
#
The example is quite primitive and basic, but can hopefully point in the right direction. I hope it helps!

Refresh the browser once on load or clear DOM

I have a dynamic MVC4, jQuery Mobile application that works for the most part quite well. I have an auto posting dropdown list that selects a list from the database via the following code.
<script type="text/javascript">
$(function () {
$("#TownID").live('change', function () {
//$("#TownID").change(function () {
var actionUrl = $('#TheForm1').attr('action') + '/' + $('#TownID').val();
$('#TheForm1').attr('action', actionUrl);
$('#TheForm1').submit();
});
});
</script>
<p>
#using (Html.BeginForm("SearchTown", "Home", FormMethod.Post, new { id = "TheForm1" }))
{
#Html.DropDownList("TownID", (SelectList)ViewBag.TownId, "Select a Town")
}
</p>
The problem is it only works properly the first time a search is performed unless I click refresh. I don’t think this has anything to do with MVC, I think the problem is with AJAX and jQuery Mobile.
Edit:
The first time I search www.mysite.com/Home/Search/2 yields a result and woks fine, but the second time something seems to be left behind in the DOM??? and it looks for:
www.mysite.com/Home/Search/2/2 also
I get 404 errors in my log and “Error Loading Page” but it still finds the results and displays the page correctly!
Then with a third search I get the error 404’s in my log and “Error Loading Page” but it has grown and now looks for:
www.mysite.com/Home/Search/2/2
www.mysite.com/Home/Search/2/2/2 also
This then continues to grow after every search until at some seemingly random point on each test, it seems to give up and I get error 505
Additional Edit:
The code works perfectly if I take jQuery Mobile out of the question
Can anyone tell me what might be going on here?
Get rid of: $(function () {
And replace it with: $(document).delegate('[data-role="page"]', 'pageinit', function () {
Please read the big yellow sections at the top of this page: http://jquerymobile.com/demos/1.1.0/docs/api/events.html
You can't rely on document.ready or any other event that only fires once per page. Instead you have to get used to using jQuery Mobile's custom page events like pageinit so your code will work no-matter when the page is added to the DOM (which you don't know when this will happen in a jQuery Mobile website). There are a ton of events, so again, please read the documentation I linked-to above.
Firstly, dynamically generated html using a server side templating engine blows. I really don't understand what value people see in it.
My guess is that it used to make sense 10 years ago before AJAX became popular, and has just hung in there ever since because people have this feeling that it is "the right way to do it". It isn't. ESPECIALLY for mobile web apps.
Secondly, it looks like you are trying to do pretty simple search. All this MVC4 garbage makes it difficult for you to see what is really happening though. You don't need to append parameters to your URL for a simple form submission like this. In fact your TownId should already be part of the POST data when you submit, so you can just remove the URL modification bit.
Alternatively, don't use a form submission, but just a GET and AJAX. I don't know what your app is doing here, but I imagine you want to display the results on the page dynamically somehow, so a GET is more than enough.
Use your developer browser tools (F12) to see what exactly is getting submitted when you do the submit - it really helps. And for your next project, abandon MVC4! "Well established design patterns" my foot.
I have been bothered by this problem for a long time
There are same select element in the DOM I think so...
and I used $('.SelectCSS:last').val()
It seen work well.
I come from China , English is poor...
I guess this is one for the future, MVC and jQuery Mobile don't seem to blend completely right now. Maybe MS's response to the issue is Single Page Applications!
SPA may satisfy Danial also?

Rails: generating URLs for actions in JSON response

In a view I am generating an HTML canvas of figures based on model data in an app. In the view I am preloading JSON model data in the page like this (to avoid an initial request back):
<script type="text/javascript" charset="utf-8">
<% ActiveRecord::Base.include_root_in_json = false -%>
var objects = <%= #objects.to_json(:include => :other_objects) %>;
...
Based on mouse (or touch) interaction I want to redirect to other parts of my app that are controller specific (such as view, edit, delete, etc.).
Rather than hard code the URLs in my JavaScript I want to generate them from Rails (which means it always adapts the latest routes).
It seems like I have one of three options:
Add an empty attr to the model that the controller fills in with the appropriate URL (we don't want to use routes in the model) before the JSON is generated
Generate custom JSON where I add the different URLs manually
Generate the URL as a template from Rails and replace the IDs in JavaScript as appropriate
I am starting to lean towards #1 for ease of implementation and maintainability.
Are there any other options that I am missing? Is #1 not the best?
Thanks!
Chris
I wrote a bit about this on my blog: Rails Dilemma: HATEOAS in XML/JSON Responses.
I came to similar conclusions. There's no incredibly clean way to do it as far as I know, because by default the model is responsible for creating a JSON representation of itself, but generating URLs is strictly a controller/view responsibility.
Feel free to look over my thoughts/conclusions and add comments here or there.

Resources