Showing posts with label Ruby on Rails. Show all posts
Showing posts with label Ruby on Rails. Show all posts

Friday, 27 April 2012

CSS positioning and Stacking images in rails.

So you are using Ruby on Rails and you want a method of stacking images on top of each other.
Your answer will probably involve CSS but many of the blog posts and Q&A posts I found weren't too descriptive so here is my shot at explaining this from the perspective of someone who doesn't use CSS often.

First a short bit on parents in CSS

When using CSS, having one style inside the other makes the top level the parent. In this example the div with the id of "container" is the parent of the div with the id of "contained".

<div id="container">
<div id="contained">
</div>
</div>
This does not work with class instead of id.

<div class="container">
<div class="contained">
</div>
</div>

And the CSS position

There are several good resources explaining position and I will just link to my favourites.
http://www.barelyfitz.com/screencast/html-training/css/positioning/

Onto the good stuff

Our CSS files are in assets/stylesheets/ and the one we are using is the application wide stylesheet application.css.scss

The technique is to have a position:relative parent container, so that all position:absolute items inside are in the same place against the relative container. Note that the container needs a size, it will not take the size of absolute children. My images are 64px*64px big so I have to force my container to be that large or the next HTML element in the flow will overlap it.
In application.css.scss

#container {
    position:relative;
    width: 64px;
    height: 64px;
}
#image {
    position: absolute;
    top: 0;
    left: 0;
}
This lets you place images with the id="image" inside a div of id="container". In my code I stack City.png vertically above Grass.png in the view. Note in versions of Rails before 3.1 you need to use :id => instead of the new syntax id:
<div id="container">
<%= image_tag("Grass.png", id:"image") %>
<%= image_tag("City.png", id:"image") %>
</div>

Sunday, 22 April 2012

Slim Rails Environment V2

Install Ubuntu Server with whatever settings you like (Default for me)

Remember that when using the xOrg system (xinit), you make it run from terminal with 'xinit' or 'startx'
You can open programs including the terminal from the right click menu in fluxbox.
You cannot copy-paste easily within xOrg unless you use terminator.

Update 24/06/12: !If you are using Bruce Scharlau's vm_template virtual box, and cannot Sudo apt-get anything due to 407 error, /etc/apt/apt.conf has the proxy defined in it and you can simply remove/replace the line as needed.

#System
sudo apt-get install xinit
sudo apt-get install fluxbox
sudo apt-get install build-essential
#Node.js  Rails will not run without a Javascript Engine
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs
#Rails
sudo apt-get install ruby1.9.1-dev
sudo gem install rails
#Using these three will install all the generic gems
#rails new cookbook
#cd cookbook
#bundle install

##Gem Specific
#Sqlite3
sudo apt-get install sqlite3 libsqlite3-dev
sudo gem install sqlite3

#Cucumber-rails
sudo apt-get install libxml2-dev libxslt-dev
sudo gem install cucumber-rails

#Postgresql gem
#Even if you do not use postgresql on your development machine, by just listing the gem anywhere in your gemfile, you need the libraries to make postgres work for bundle install. This is needed for Heroku.
sudo apt-get install libpq-dev #Note libpq NOT libpg

##Other Programs
#Terminator (Better terminal)
sudo apt-get install terminator

#Google Chrome (web Browser)
sudo wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get install google-chrome-stable

#sqlitebrowser (SQLite3 browser)
sudo apt-get install sqlitebrowser

#git
sudo apt-get install git



#Komodo ~Broken
~I have not yet got this working on xinit. Use Nedit or nano instead.
Edit: Or if you are using Ubuntu in a VM, start up a shared folder and run Komodo outside the VM

Aded 24/06/12:

My Workflow


Since this is useful and interesting to people, here is how I work:

When working, I have the virtual machine open on 1/3 of my screen. In it I have terminator open, with a tab for all git commands, a tab for all rails, system and developement commands, a tab for running rails s if I am testing in chrome, and a tab for running guard in (guard is a gem that automatically runs all rails tasks on file change) I will open a chrome window at the bottom of this area if I need to look at my app outside testing.

The only two changes I have made to Bruce's VM is I have made a symlink from /media/sf_vm_shared to ~/shared so it is in my home folder, and I have removed the proxy line in /etc/apt/apt.conf since I do not bring my desktop onto campus.

The remaining 2/3 of my screen has komodo edit running in the windows environment which edits the files through the shared c:/vm_shared folder.

Wednesday, 28 March 2012

Stumbling blocks

I've been bumbling through a few self-made hurdles the last few days and they all unraveled when I sat an unknowledgeable friend next to me and spoke at him as I worked through my problem. This is what I call the rubber duck method.

New knowledge 1)
@thing.user_id = User.find_by_email(params[:legitimate_user_email])
The flaw here is that I this caused me a really hidden error.
I thought assigning it to a user would use the ID since that is how the models for each of these is linked together, but instead it kept returning ID1 instead of throwing an error.
@thing.user_id = User.find_by_email(params[:legitimate_user_email]).id
WOW that was a simple flaw but it didn't show up because it threw no error.
I was almost defeated by 3 letters and I have never been so embarrassed.

New knowledge 2)
Redirect_to :back
the :back parameter is really cool. I was passing a param back to the controller to know where to redirect my users back to, which was causing me to use POST and GET params at the same time, when I could have used :back all along. Code is now prettified and users now cannot redirect themselves to nasty places using an obvious param in the url.

New knowledge 3)
rake db:drop db:create db:migrate db:seed db:test:prepare
I should have a macro for this or something. Saves me time and attention knowing I can chain rake tasks now. Minutes are saved every day.

New knowledge 4)
before_filter do |c|
    c.send(:authorize, "admin")
end
Passing params to the before_filter method is really quite awesome and very helpful if you are writing your own permissions from scratch. I had no idea what I was going to do to get round this as there was no way I was going to explicitly name every method. I would miss my deadline by months even attempting it.

New knowledge 5)

require 'rubygems'
require 'factory_girl_rails'
Loading a gem for local use in a file is not only useful when you want to use a gem outside its intended scope, but apparently there are optimization benefits in loading the gem only when needed too! (according to someone on stack overflow, but I haven't tested it and he also said it was a maintenance nightmare!)

New knowledge 6)
Rails.root.join('folder','file_in_folder.rb')
The cross platform version of  "%Rails_root%/folder/file_in_folder.rb"
Both allow you to rummage around anywhere inside of your own rails directory but the first works on operating systems that do not use '/' as a separator.

Altogether, I'd say this has been a massively successful week. I've been using I18n.translate aka t ("some.location.in.config.locale_name.yml") which is extremely cool, and I'm expanding my use of capybara and TDD.
Now I write it down, I am learning quite a lot in a short amount of time.

Edit:
New 7)
I didn't think it was from this week as it seems so long ago, but commit logs say otherwise.
<%= collection_select("group", "permission_id", @permission, "id", "name") %>
Selecting from a collection is fun, I'm not sure if it is badly documented or I was looking for all the wrong keywords.

Sunday, 25 March 2012

Seeding the Test Database

Edit: this post was edited with new information as it was found. As such it is a mess. There are two solutions to loading the same seed data in test as the other environments: Loading your seeds.rb from factories in the spec, or loading your seeds into the testing environment. I prefer the first option as you get to make your seeds with FactoryGirl and it gets validated and if you are loading your seeds in spec, you need to call the method to load it before(:all) every time.

I was wondering why some of my tests were not passing after a Rake db:test:prepare
Turns out it clears the database, and the only way I have to get it back using the seeds.rb file is with RAILS_ENV="test" Rake db:seed which seems cumbersome and not really railsy at all.

As a bonus, after I run RAILS_ENV="test" Rake db:seed, I then fail a lot of tests. It seems that seeding the test database breaks FactoryGirl's creates.

Is there a way for me to have my seeds and test them?

At the moment I am looking into ways to get seeds.rb to load a FactoryGirl method that I can use to also populate the test database separately. That seems like an easier approach to loading my seeds.rb into FactoryGirl as it causes already passing tests to fail and behave differently in test to development which is obviously bad.

Asking others seemed a good idea:
http://stackoverflow.com/questions/9861075/how-can-i-load-seeds-rb-into-the-test-database-without-breaking-factorygirl

But in the end I managed to weedle out 2 possible answers myself:

1) Loading Seeds from Spec

In Spec/helpers.rb:

def seed_data
require Rails.root.join('db', 'seeds.rb')
end

2) Loading Spec from Seeds

In Seeds.rb


require Rails.root.join('spec', 'helpers.rb')
require 'rubygems'
require 'factory_girl_rails'
seed_data

In Spec/helpers.rb


def seed_data
  Factory.create(:admin)
  #Create all your objects
end

Wednesday, 21 March 2012

Rails on Logging Passwords

I was just reading through security issues for my app as it is good to do from time to time, just to keep on my toes when I spot this:
"By default, Rails logs all requests being made to the web application. ... Encrypting secrets and passwords in the database will be quite useless, if the log files list them in clear text."


I immediately jump to my development.log to check out if my passwords are showing and lo and behold on line ~1000
"Parameters: {"utf8"=>"✓", "authenticity_token"=>"8DznfYV1t1Mb+S/3MzMaZ9Clf/FuO894UkYFoBfu0Ug=", "user"=>{"email"=>"a@a.a", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "language"=>"en"}, "commit"=>"Created User"}"

Thank you Rails 3.2 !


Note1:
If your passwords are not hidden, the fix should be something like the following line:
config.filter_parameters << :password

Note2: It looks like by default Git does not push up log files in Rails, but you should double check all your public Github log directories just in case

Wednesday, 14 March 2012

A Newfound Love of Testing

So I will say it from the start, I dislike cucumber with a passion. It just feels like another language I need to write, then I end up writing code to "pass" my tests where I actually end up testing my tests using the code I would have originally wrote.

This meant that all that happened was I sat in the back of lectures thinking "Nope Nope Nope", and that it would just double my work load.
On top of that, cucumber-rails has the added bonus of breaking all machines running windows. Not really an appropriate tool to pick to teach us TDD on windows university PCs with.

Then along came capybara.
The great thing is you can basically write all your tests as variations on a few commands.

  • Click_on "some_button_id"
  • Page.should have_content  "some #{dynamic} content" 
  • visit some_path
  • current_path.should eq some_path
  • fill_in "field name", :with => "some #{dynamic} content"


That is pretty much it. With capybara, it is like sitting behind someone telling them what to do, it is no longer complicated or cumbersome and your testing doesn't need to be complicated buggy code of its own. It is REALLY simple and I like it. I like it a lot. It even encourages you to make your HTML better documented as if there is a page with a hundred DELETE buttons, you don't want to accidentally click on the one for yourself.

Mix it with Factory_Girl and you are flying in seconds!

Wednesday, 7 March 2012

A small note on gem dependencies.

It is sad that a really cool gem like Twitter-Bootstrap-Rails depends on Less-Rails, it is in turn that Less-Rails depends on Less, and it is a shame that Less depends on Libv8, and again that Libv8 depends on JS gems other than execjs.
This means that it does not autodetect a javascript engine like nodejs which means that they chose a specific gem (therubyracer) that only works on linux.

This chain of dependencies is unavoidable, I know. And less seems quite cool though I prefer the meta-programming like scss way more, but forcing gems built on gems build on therubyracer locks it unavoidably to mac or linux.

Edit:


Turns out there is a version of Twitter-Bootstrap that uses static CSS, which can be used with this in your gemfile: gem 'twitter-bootstrap-rails', :git => "git://github.com/seyhunak/twitter-bootstrap-rails.git", :branch => "static"

Wednesday, 29 February 2012

Developing SQLite3 and Postgres for use with Heroku

So Heroku's FAQ on using SQLite3 alongside Postgres basically consists of "Don't", so in the usual spirit of things, I'm out to make it work. Why you want to do this is up to you, for me it is because the Postgres gem forces the JSON gem to install with Native Extensions instead of just using JSON and all the university machines have ANSICON which breaks JSON via a registry entry. Also even if it did work I don't think they will let me install Postgres on their machines so SQLite3 is a must.

There were many pitfalls on the way to discovering this since I was stubborn but it turns out there is a really pretty and simple way to do this.
We must separate production from development and test as Heroku uses production.

In gemfile

group :production do
  gem 'pg'
end


group :development, :test do
  gem 'sqlite3'
end


And that is it.

Bask in Rails server for development in SQLite3,

Heroku login, Heroku create --stack cedar, Git push heroku master, Heroku run rake db:migrate, Heroku open.

Then revel in your working heroku production environment.

I even went so far as to play with many things like Bundle install --without production and rake db:migrate RAILS_ENV=development but you should not need to play with such things.

That is all.

Tuesday, 28 February 2012

My exact RoR environment (Code Only)

sudo apt-get install xinit
sudo apt-get install fluxbox
sudo apt-get install ruby1.9.1-dev
" permission denied - /var/lib/gems " if not using 'sudo' for gem install
sudo gem install sqlite3
if "Building native extensions. This could take a while...
ERROR: Error installing sqlite3:
        ERROR: Failed to build gem native extension.
/usr/bin/ruby1.9.1 extconf.rb " then sudo apt-get install sqlite3 libsqlite3-dev
sudo gem install rspec
if "make
sh: make: not found " then sudo apt-get build-essential
sudo gem install rails
sudo gem install rspec-rails
sudo gem install cucumber-rails
if "libxml2 is missing." then sudo apt-get install libxml2-dev
if "libxslt is missing." then sudo apt-get install libxslt-dev
if "could not find gem 'jquery-rails (>=0) ruby' in any of the gem sources listed in your Gemfile."
"/var/lib/gems/execjs-1.3.0/lib/execjs/runtimes.rb:50:int 'autodetect': Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)" then
sudo add-apt-repository ppa:chris-lea/node.js
if "the program 'add-apt-repository' is currently not installed."
sudo apt-get install python-software-properties
sudo apt-get install nodejs
startx
Add editor of choice and done.