Marko Ćilimković
Marko Ćilimković

Reputation: 763

Better way to use a json object in a Rails application

In my Rails app I have many categories that have many clients. It also supports switching languages.

The categories are shown in the navigation of the app and I want to make a custom dropdown that contains the clients of that category. It will be created when a user hovers on some of those categories.

I've created a new resource that is doing the job of fetching the clients that belong to the hovered category, but I'm having trouble making those clients linkable due to the internationalization.

This is the javascript code:

$(function () {
    $(".nav_category").hover(function () {
        category_dropdown = $(this).children(".category_dropdown");
        clients_from_category = category_dropdown.children(".clients_from_category");
        category_dropdown.toggle(0, "hidden");

        $.get($(this).data("url"), function(response) {
           client_name = response[0]['translations'][0]['name'];
           client_picture = response[0]['pictures'][0]['image']['thumb']['url'];

            html = "<a href='/clients/"+response[0]['id']+"' class='nearest_client'>";
            html += "<img src='" + client_picture +"'>";
            html += client_name;
            html += "</a>";

            clients_from_category.html(html);
        });
    }, function() {
        $(this).children(".category_dropdown").toggle(0, "hidden");
    })
});

The problem here is that I get the links displayed like this:

<a href="/clients/157" class="nearest_client">
  <img src="/uploads/picture/image/361/thumb_image.jpg">Client name
</a>

Notice there is no locale set. It should be like:

<a href="en/clients/157">

Is there a way to get to the set locale? Or am I approaching this problem in a bad way? What is a better way of setting a listener on a div and creating the needed DOM elements from the returned JSON object?

Upvotes: 0

Views: 80

Answers (2)

Marko Ćilimković
Marko Ćilimković

Reputation: 763

Maxcal was really helpful with his suggestion to use ActiveModel::Serializers, but after I made the necessary changes a lot of my other resources in the API part stopped working properly.

For a quick fix on this I used another data attribute that I passed to javascript:

html = "<a href='"+ $(this).data("language") + '/clients/' + response[0]['id']+"' class='nearest_client'>";

Upvotes: 0

max
max

Reputation: 102423

The solution is use the Rails link helpers to add the url or path to the JSON output.

If you are using JBuilder (which is installed by default):

# /app/clients/views/show.json.jbuilder
json.id @client.id
json.name @client.name
json.path client_path(@client)
json.url client_url(@client)

But I would recommend using ActiveModel::Serializers:

class ClientSerializer < ActiveModel::Serializer
  attributes :id, :name, :path, :url

  def url
    client_url(object)
  end

  def path
    client_path(object)
  end
end

See the RailsCast for basic use instructions.

Then you would use it in your javascript like so:

$(function () {
    $(".nav_category").hover(function () {
        var category_dropdown = $(this).children(".category_dropdown");
        var clients_from_category = category_dropdown.children(".clients_from_category");
        var category_dropdown.toggle(0, "hidden");

        $.get($(this).data("url"), function(response) {
            var client = response[0];
            var client_name = client['translations'][0]['name'];
            var client_picture = client['pictures'][0]['image']['thumb']['url'];
            var html;

            html = "<a href='+ client.url +' class='nearest_client'>";
            html += "<img src='" + client_picture +"'>";
            html += client_name;
            html += "</a>";
            clients_from_category.html(html);
        });
    }, function() {
        $(this).children(".category_dropdown").toggle(0, "hidden");
    })
});

On a side note - you need to use the VAR keyword when declaring variables in javascript. Otherwise they are created as globals which is a really bad thing. Use JSLint or strict mode to catch misstakes like this.

Upvotes: 1

Related Questions