Tag Archives: rails

Fixing ugly Rails uglifier error

More in the notes-to-self to unblock problems with Rails (and ruby in general).

I have just been working on a new project and got the following error when trying to create the very first scaffold:

rails g scaffold crossword_setters name:string setter_type_id:integer 
/home/julian/.rvm/gems/ruby-2.3.0/gems/bundler-1.11.2/lib/bundler/runtime.rb:80:in `rescue in block (2 levels) in require': There was an error while trying to load the gem 'uglifier'. (Bundler::GemRequireError)

Okay? So this is telling me that I am missing a dependency, but keeping the essential details hidden.

A quick bit of searching suggests that uglifier depends on a JavaScript library; I typically  use ‘therubyracer‘.

I was still getting the error after installing both the ‘therubyracer’ and ‘libv8′ gems, having neglected to make sure that it had been enabled in the Gemfile. This last step is the fix.

Advertisements

Giving up on rails on Docker

Having gone through the process of preparing s Rails image from a ruby build has ballooned out to over 1.2GB even after removing the compiler and associated packages.

I even tested running a bundle update to identify the gems that need native compilation: mysql2, bcrypt, therubyracer.

And then… And then after downloading the application running the bundle update borked when bcrypt 3.1.9 is needed as a dependency instead of the 3.1.10 installed. Given the time it takes to compile gems, it’s not reasonable or sensible to try and stay on top of deploying rails applications to a container.

Okay, so we’ll try to do a WordPress deployment instead.

https://docs.docker.com/compose/wordpress/

Custom generators

Another aide-memoir (based on http://guides.rubyonrails.org/generators.html)

Having created templates in libs/templates/erb/scaffold (for views) and lib/templates/rails/scaffold_controller/controller.rb simply run,

rails generate scaffold User name:string …

and the views and controller will contain the templated files. There are a lot more we can do with generators but this is a good start.

Rails and JQuery autocomplete

My last post was for adding a tokeninput field to form that could be dynamically updated, but I’ve kinda used them inappropriately, for single-value text boxes.

So I got brave and decided to have a go at implementing the JQuery autocomplete widget to replace a slightly unwieldy and inflexible select list.

This time the Gemfile needs to include a bit more,

# Use jquery as the JavaScript library
gem 'jquery-rails'
gem 'jquery-ui-rails', '~> 4.0'
gem 'jquery-modal-rails'
gem 'jquery-tokeninput-rails'

(I have left in the modal and tokeninput items used elsewhere). Notice that I have fixed the jquery-ui-rails to version 4. This is because version 5 is out and that’s seriously incompatible with a lot of existing JQuery gems; I did experiment with using V5 (or jquery.ui.rails or something like that) but there was no way I could get any of the ui elements working. All my other RoR sites are based around v4 and I’m determined to maintain a consistent platform across the applications.

(I’m also using turbolinks – not sure why – and that seems to have its own problems with JQuery)

The general methodology with the route, controller action, JSON template are the same as before,but this time the JQuery call is,

$( "#phone_ext_number" ).autocomplete({source: '/phones/'+$("#phone_sub_department_id option:selected").val()+'/extension_list.json'});

With the _form partial containing,

<%= f.text_field :ext_number, {:size => 6, "data-pre" => Extension.select(:extension).where(id: @phone.extension_id).map(&:extension).to_json, :class => "phonebook"} %>

This is so much better than an auto-populated select list, because the data to be inputted falls within well-defined ranges and known beforehand. It’s easy to type in for the user, but the autocomplete only lists extensions not already assigned and uses the entered digits to further constrain the list, from which a user is free to select. It also means I can do a fair bit of data validation to prevent bad data going in; this application is replacing a legacy website that is notorious for inaccurate records and we’re working on the principle of making it harder to submit bad data, but easy to enter good stuff.

I’m quite pleased with the result and will use the autocomplete elsewhere, replacing some of the wayward tokeninput laziness.

JQuery for dynamic updates in Rails

Posted as an aide memoire because I’ll forget what project I’ve used it in and how to do it; I’m a part-time RoR coder, not my day job, though the stuff I am writing is important to other people’s operational work.

To create a select dropdown of items when another form element is changed.

Include some JQuery gems (I suspect this is where all the hard work is done and I’m just adding the easy stuff),

# Use jquery as the JavaScript library
gem 'jquery-rails'
gem 'jquery-modal-rails'
gem 'jquery-tokeninput-rails'

It could pay to be careful with this because of October 2014, version 5 of jquery-rails is out and comes with a lot of changes and breakage. Another post on this soon.

Declare a variable as an anonymous function call (closure). Then register a handler for the change event with another closure. Capture the selected value of the form element that triggers the event (perhaps with a sensible default), issue an JSON request to a controller method and loop through each of the returned values and append them to the select list. Finally register the closure variable to load on the page.

var ready = function() {
 $("#model_name_trigger_id").change(function() {
 var sd = $("#model_name_trigger_id option:selected").val();
 if (!sd) {
 sd = 1;
 };
 $("#model_name_field_id").html('');
 // make a GET call and replace the content
 // If not using a nested model, use,
 // $.getJSON( '/controller_name/list_of_items.json', function(data) {
 $.getJSON( '/controller_name/' + sd + '/list_of_items.json', function(data) {
 for (var x in data) {
 $("#model_name_field_id").append($('<option></option>').val(data[x].id).html(data[x].label));
 };
 });
 });
};
$(document).ready(ready);
$(document).on('page:load', ready);

Define a route for the JSON request to the controller

match 'controller_names/:id/list_of_items', :to => 'controller_names#list_of_items', :via => [:get, :post]

This will capture the JQuery ‘sd’ variable as an :id param in the controller for the nested model
but remove the ‘:id’ if not just using a single model.

Write a method in a rails controller

def list_of_items
  // Grab the params submitted in the JSON request
  i = params[:id]
  @items = Item.nested_model_scope(i)
  respond_to do |format|
    format.html
    format.json { render json: @items } 
  end
end

Then prepare a JSON template in the views,

json.array! items do |item|
  json.extract! item, :id, :label
end

This might not be 100% accurate in terms of the names but it’s enough to the serve the purpose of reminding me of the what I need to include when I do this next time.