Category Archives: Ruby on Rails

Saying goodbye to Rails

I give up.

Everywhere I look suggests that what I have should be enough for this to work. But it isn’t.

And since this is a fundamental feature of the project, and what with the still patchy cross-browser performance of JQuery auto-select, it’s time to abandon Rails and look for another framework.

So, I will be taking a pause while I get Django up and running. Rails is no more.

Wot, no controller?

While considering where I was going wrong with my Rails project, I figured that since I had the model and the views covered, I ought to give some consideration to the controller.

Then it occurred to me that the reason why no form elements were being shown on the new commission page was because I hadn’t created any! The standard scaffold controller action can be a little basic with show and edit completely blank.

But the ‘new’ controller does create an object and this is where the form elements com from. And in earlier tests, I had seen that I could use a build method to create the nested attributes. This should be easy.

Surely all my controller needs is:

 def new
   @commission = Commission.new
   @commission.build_activity
 end

So why does that give me the following error:

undefined method `build_activity' for #<Commission:0x007f9e10be7020> Did you mean? build_commission_type

I can change the controller as suggested,

 def new
   @commission = Commission.new
   @commission.build_commission_type
 end

And although the page loads, there are no form elements displayed. It’s wrong anyway, so I’m not bothered about that.

Perhaps the problem boils down to using a word that that plurals with ‘ies’ and that needs to be reflected in the appropriate places: sometimes singular sometimes, plural, other times pluralised. Sometimes errors, sometimes nothing.

This is the Rails way: everything’s a battle. Every step of the way.

3 sources, all slightly different, none work

Now on the case with http://apidock.com/rails/v4.2.1/ActionView/Helpers/FormHelper/fields_for (yes, I know, Rails 4, probably isn’t supported in 5) and mentions more possibilities that probably aren’t relevant, but don’t work anyway.

I mention it here because if (I’m not confident enough to say when) I get this working I will be needing to auto-populate some fields (am I mad!) and there might be value in the comments.

It’s another one of those times when it’s clear that I’m doing something wrong (other than actually attempting to do this) but I have no idea what and very little indication of where to start looking. For all the times that development can accelerate with Rails, there are these occasions when it grinds to a halt and you’re never actually sure how it got fixed.

It couldn’t last

It didn’t take long for my development with polymorphic associations and forms to founder.

The very next stage after my last post on the matter, in fact. And I now have a second reference source that, while providing an additional nudge, isn’t enough to see me through the current block.

To be able to nest the activity section on the commission form, we need to tell the commission model to accept activity fields,

accepts_nested_attributes_for :activities

(I originally hd this as :activity after the model name, but it gave a missing model error; then my initial hunch was probably that accepts_nested_attributes_for was no longer supported in Rails 5; these things rarely work for very long).

A quick search on the topic of continued rails support for accepts_nested_attributes_for took me to https://rubyplus.com/articles/3681-Complex-Forms-in-Rails-5, which is a nicely written page which only backs up my original source. Curiously, however, it includes a step that shows successful data posts before they’ve been added to the form.

Then we simply add the following to the commission form,

 <% f.fields_for :activities do |act| %>
 Title: <%= act.text_field :title %>
 Details: %= act.textarea :details %>
Number of slots: <%= act.number_field :number_of_slots %>
 Min slot separation: <%= act.number_field :min_slot_separation %>
 <% end %>

Then nothing. No errors, log messages or anything. Nothing. Nothing ever works the way it’s described and a heavy price is to be paid for every advance.

 

Rails polymorphic associations

The first in a likely series of posts regarding polymorphic associations in Rails that will illustrate my hitherto lack of understanding about how they work and my (hopeful) development to being able to use them effectively in my current project.

I’m going to need reminders and reference points when I get deeper into the project and start to make progress. I don’t necessarily expect this to be of use use to anyone else.

First off, I’m using https://6ftdan.com/allyourdev/2015/02/10/rails-polymorphic-models/ as a reference; so far it’s working well for me.

Start with a new git branch in case things don’t work out.

$ git checkout -b polymorphic_activities

The activities table already includes activityable_type and activityable_id columns but I needed another migration to the table to do the half-baked ideas I had before/

The Commission model includes,

class Commission < ApplicationRecord
belongs_to :request
 belongs_to :commission_type
 has_many :activities, :as => :activityable, :dependent => :destroy

The Activity model includes

class Activity < ApplicationRecord
 validates :title, :presence => true, :uniqueness => true
 validates :activityable_id, :presence => true
 validates :activityable_type, :presence => true
 
 belongs_to :activityable, :polymorphic => true

And we can test this with the Rails console with something like,

2.3.3 :002 > commission = Commission.first
2.3.3 :005 > commission.activities.build(title: "Background layers", details: "do some prep layers", number_of_slots: 3, min_slot_separation: 3).save

And we get an entry in the activities table with activityable_type set to Commission and activityable_id set to the id of the commission. Looks promising.

The main point at this stage is that I can bin the activity_commission, activity_other, activity_teaching tables (with ActivityCommission as the activityable_type) and just use Commission, etc. I’m beginning to see how this might work for all the other activity-based relationships I need to model. No need to abandon the project just yet.

Automating builds and testing with Jenkins

Now, I’m more than well aware that I’m on a well-trodden path here, but this is more as a reminder of some basic setup for future use.

With previous Rails projects I have undertaken, I have tried to incorporate the testing after a significant amount of the code has been written, making a serious test scenario unfeasible.

With my latest project, however, I’m taking the time to include testing from the get-go. So, with the first few models created I have taken the time – about 50% of the project time thus far – to get a set of successful model and controller tests; there may be a separate posting to cover this.

With testing in place and with GitHub being used as the SCM, I’m in a position to automate the build and test process. I’m thinking of deploying the application to a personal AWS account and building a pipeline to build and deploy after commits.

Anyway, using my Arch Linux desktop machine as the testing server, I installed Jenkins and started the service. I started working from the getting started guide at https://jenkins.io/ but didn’t fancy getting to grips with Groovy and the pipeline.

I found a simple guide for configuring Jenkins to build and deploy a Rails project and decided to see if I could a tangible result.

The Jenkins installation creates a user account with a home directory, /var/lib/jenkins, and to work with a Freestyle project we need a .bashrc to set up the environment for the build script.

COMMISSIONS_USER="mysql-user"
COMMISSIONS_PSWD="mysql-pssword"
COMMISSIONS_HOST="localhost"
COMMISSIONS_DB="test_database"
TEST_SECRET_KEY_BASE="... random.charcters.for.secret.key..."
MYSQL_SOCK="/path/to/mysqld.sock"
export COMMISSIONS_USER COMMISSIONS_PSWD COMMISSIONS_HOST COMMISSIONS_DB TEST_SECRET_KEY_BASE MYSQL_SOCK
echo "Exported Rails and MySQL environment for $LOGNAME"

These are to match the environment references in the database and secrets YAML files from the repository; the last line is helpful for checking the console output.

The build script then becomes the following,

#!/bin/bash

export RAILS_ENV=test
. $HOME/.bashrc

cd . # Force RVM to load the correct Ruby version

/usr/bin/bundle install
/usr/bin/bundle exec rails db:create db:schema:load db:migrate
/usr/bin/bundle exec rails test

Now, because I typically use rvm for the ruby install for my account, the gems required fo the application aren’t generally available. This means that the bundle command will require privilege escalation to install the gems and we need to permission the jenkins account needs an entry or two in /etc/sudoers (which can be removed after the first bundle has completed, but will be required for each new gem).

jenkins ALL=NOPASSWD:/usr/bin/bundle
jenkins ALL=NOPASSWD:/usr/bin/gem
jenkins ALL=NOPASSWD:/usr/bin/rake

And with all that in place we can ask Jenkins to build now and get a clean run and with  daily schedule for builds we can start on the development cycle making sure we continue to test as we go.

References

http://nithinbekal.com/posts/jenkins-rails/ – a basic guide (for Ubuntu) adapted for my setup

Rails 5 jQuery datepicker

I’m embarking on another Rails project and of course there’s been a version bump that I’m going to have to get used to; hopefully I can still remember some of the old stuff.

One of the requirements for the front page is a date selector and since I’ve used a bit of jQuery before…

But this is Rails and life is never that simple.

It starts easily enough and a quick search leads to http://www.rubydoc.info/gems/jquery-ui-rails/5.0.5 which suggests adding a gem, a line in application.js and application.css and Bob’s your uncle.

What the page fails to mention is that taken at face value it doesn’t work. And it doesn’t give an example of how it might be used in a Rails template. There is a note on the page about steps required for certain versions, but it’s not clear that this is actually for current works not old versions.

It turns out that just including ‘gem jquery-ui-rails’ will install version 6 and this isn’t good. What we really need is

gem 'jquery-ui-rails', '5.0.5'

And then, application.js gets the following,

//= require jquery-ui/datepicker

And application.css is treated with,

*= require jquery-ui/datepicker

And with slight trepidation, some CoffeeScript (I fail to see the point of a language to write languages; this isn’t assembler),

jQuery ->
 $('#datepicker').datepicker();

And swapping the date_select helper in the form template with,

<%= f.text_field :due_date, :id => "datepicker" %>

And it works! It’s the “, ‘5.0.5’ that makes the difference.

References

http://stackoverflow.com/questions/15727660/rails-jquery-ui-datepicker – for help with the general approach.

http://stackoverflow.com/questions/42495010/couldnt-find-file-jquery-ui-datepicker-with-type-application-javascript – this page is in response to the displayed by following the default instructions and references the easily-missed version warning.

Working toward a testable Sinatra application

One of the prime goals I had when starting writing a simple Sintra application was to make sure unit testing was done from the start, a vague sort of TDD, given that I’m not  professional developer and I’m not mad about ideaology; I’d had made very little trying to build unit tests for Rails applications, especially when it comes to sessiosn and authentication. No testing, no application.

Even though Sinatra is a small footprint and quick to get going, I still found it very opaque and the Rack test library very secretive and deceptive. It took me 10 days trying to figure out 4 tests for my application, though, as painful as it was, I do have a better (and more coherent – never my strong point) application as a result.

Ultimately, however, I found it much easier to design the testing code for the transactions I wanted using curl because it is so much easier to figure out what is going on.  I really wanted to run a command that I *knew* was submitting data in the format I wanted so that I could sort the routing code around it. Something like,

curl -v http://localhost:4567/package-inventory/packages/new -H 'Content-Type: application/json' -d '{"hostname": "thisbox", "packages": {"first-package": "4.9.", "my-package": "1.2.", "your-package": "4.5.6-0."}}'

Once the server is reponding as expected, it can easily be added to an integration test with a snippet like

jdata = {}
 jdata[:hostname] = hostname
jdata[:packages] = {}
 ["first-package 4.9.0", "my-package 1.2.3", "your-package 4.5.6-0.1"].each do |pkg|
  jdata[:packages].merge! Hash[*pkg.chop.split(/ /)]
 end

The submission can be completed using something like

 request = '/package-inventory/packages/new'
 headers = { 'CONTENT_TYPE' => 'application/json' }
 post request, jdata.to_json, headers
 assert last_response.ok?

On the receiving end of the POST we hve to remember that the incoming data is a SringIO object and as such is accessed like a file stream,

jd = request.body.read.to_s
 jdata = JSON.parse jd

I initially made the mistake of treating the request body as an array to be referenced several times and wondering why it had disappeared: assign it to a variable an be done with it! I also spent some time trying to access the submission through the params hash without realising that that only applies to symbolised references on the incoming request.

After parsing, we then have our data to do as we please. Based on an example, I maintained the return messages (for status or data return) as a hash finishing off each route with,

return_message.to_json

helping ensure that all inbound and outbound requests are in the same format.

I still wouldn’t say that I’m fully comfortable with the unit tests, but they do work mostly as expected, even for failure conditions.

But as a comparative exercise, I’m going to produce Python version of the same service using Flask and a unit test process, bearing in mind that this will be my first ever Python program; the early signs are quite promising.

References:

I found the last comment at http://stackoverflow.com/questions/18449428/sinatra-unit-test-post-with-json-body (eventually) useful, but ignore the comment advising against using JSON to transfer data; such is the variability of the Stack.

 

 

 

Posting JSON to Sinatra using curl

Because of the difficulties (opacity) of trying to develop unit tests with Rack on a Sinatra application, I decided to try get something working with curl: we have much better control of the post process and is something we can actually troubleshoot.

Of all the posts I have seen regarding to Rack applications, the one that sticks with me is http://lightyearsoftware.com/2013/02/sending-json-post-data-in-an-integration-test http://lightyearsoftware.com/2013/02/sending-json-post-data-in-an-integration-test/, simply because the author says that it is not straightforward and doesn’t expect it to continue working with future versions of Ruby or Rails.

I’ll put together another post shortly describing in a bit more detail, not just the POSTing, but the receiving end as well. It’s been painful.

Why so hard to do the right thing?

Just when I thought I’d found something really cool in Ruby that was going to produce simple applications and exploring a development lifecycle…

I really, really want to be able to write unit and integration tests for teh code I produce. With Rails, rspec is a nightmare, especially when combined with sessions and authentication.

So I take a step down to Sinatra and Rack. I get some simple code for a little service and the GET request for resource works as expected. But 3 days trying to get the unit test function to be able to post data is just too much. None of the official documentation mentions it never mind examples; so many variations on StackOverflow; verbatim copied code from blogs that has syntax errors.

It’s not even that my  server app can’t process POST data, it is that the unit test gem makes it impossible to debug the transfer, whether or not I’m a numpty.

This time I’ll abandon the project and the follow-up applications I had in mind for Sinatra and write it off as another Ruby dead-end. I’m sure people do get it working but I give up.