Showing posts with label Rails 3. Show all posts
Showing posts with label Rails 3. Show all posts
Thursday, 16 August 2012
Rails Time
Earlier in the month I was experiencing some odd behaviour in ruby.
irb(main):002:0> DateTime.now
=> Mon, 13 Aug 2012 17:04:34 +0100
irb(main):003:0> DateTime.now + 2.days
=> Sat, 22 Sep 2485 17:04:42 +0100
DateTime is a class with a limit that goes up to year 9999 and as far as I can tell isn't stored as seconds, the more commonly used Time class is measured in seconds and goes up to 03:14:08 UTC on 19 January 2038 on 32 bit (thanks Wikipedia). All the Railsy time goodies (example, 5.weeks.from_now) are measured in seconds too, and so are only compatible with Time (or Date) class but not DateTime.
It is almost misleading that ActiveRecord says time is stored as DateTime in databases, it is actually stored as Time.
References
DateTime
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/date/rdoc/DateTime.html
Date
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/date/rdoc/Date.html
Time in Core
http://ruby-doc.org/core-1.9.3/Time.html
Time in Date. The difference is this has to_date, to_time, and to_datetime methods.
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/date/rdoc/Time.html
Tuesday, 10 July 2012
Foolproof FactoryGirl Sequence
Turns out Sequencing in FactoryGirl isn't as easy as it used to be.
Factory.next has been deprecated and the two obvious ways to make a sequence now throw Trait error or Attribute already defined error "FactoryGirl::AttributeDefinitionError"
The problem with this first approach is name. In a normal sequence you would just say name but I want to use it in the description too. This somehow makes FactoryGirl believe name is a trait.
FactoryGirl.define do
sequence(:code) {|n| "#{n+1000}"}
factory :course do |u|
name "CS#{ generate :code }"
description "#{name}, 1st year, 1st semester, Foundation Of #{name}"
end
end
This next example has a problem with the description line. This causes the description to generate 2 more names and throw an AttributeDefinitionError because you now have more than 1 name generated.
For some reason you cannot get around it by making the name line name = Factory.generate :name because name becomes a Trait again.
FactoryGirl.define do
sequence(:name) {|n| "CS#{n+1000}"}
factory :course do |u|
name
description "#{name}, 1st year, 1st semester, Foundation Of #{name}"
end
end
This is the only thing that works. Static forcing FactoryGirl to use the already defined name again using the |a| block in description. It isn't as pretty as it could be but I have to live with it unless someone can tell me a better way. There is probably a solution where you use an after_build tag but that makes it longer and more complicated unnecessarily and it would still be ugly.
FactoryGirl.define do
sequence(:name) {|n| "CS#{n+1000}"}
factory :course do |u|
u.name
u.description {|a| "#{a.name}, 1st year, 1st semester, Foundation Of #{a.name}"}
end
end
Factory.next has been deprecated and the two obvious ways to make a sequence now throw Trait error or Attribute already defined error "FactoryGirl::AttributeDefinitionError"
The problem with this first approach is name. In a normal sequence you would just say name but I want to use it in the description too. This somehow makes FactoryGirl believe name is a trait.
FactoryGirl.define do
sequence(:code) {|n| "#{n+1000}"}
factory :course do |u|
name "CS#{ generate :code }"
description "#{name}, 1st year, 1st semester, Foundation Of #{name}"
end
end
This next example has a problem with the description line. This causes the description to generate 2 more names and throw an AttributeDefinitionError because you now have more than 1 name generated.
For some reason you cannot get around it by making the name line name = Factory.generate :name because name becomes a Trait again.
FactoryGirl.define do
sequence(:name) {|n| "CS#{n+1000}"}
factory :course do |u|
name
description "#{name}, 1st year, 1st semester, Foundation Of #{name}"
end
end
This is the only thing that works. Static forcing FactoryGirl to use the already defined name again using the |a| block in description. It isn't as pretty as it could be but I have to live with it unless someone can tell me a better way. There is probably a solution where you use an after_build tag but that makes it longer and more complicated unnecessarily and it would still be ugly.
FactoryGirl.define do
sequence(:name) {|n| "CS#{n+1000}"}
factory :course do |u|
u.name
u.description {|a| "#{a.name}, 1st year, 1st semester, Foundation Of #{a.name}"}
end
end
Monday, 2 July 2012
Importing a CSV File from Upload in Rails >= 3
For some reason I found the documentation for CSV's really bad!
What I wanted to do is accept a file from a form and parse it into a list of users to be added to the database without saving the CSV file. (Note: I DO save the file via the Paperclip Gem for logging purposes but I do all the processing from the file before it is saved to the database.)
When you have uploaded the file using Form_Tag, the file is usually in params[:name] where :name is tag you gave to file_field_tag :name
If you are using a Form_For, which by the way is strange if you do not intend to save it to the model in question, the file will be in params[:model][:name] from f.file_field :name
The magic part is to actually get to the file you need to call .read on it.
In the View remember to make it multipart to accept files.
<%= form_for @model, :html => { :multipart => true } do |f| %>
<%= f.label :file %><br />
<%= f.file_field :file %><br />
<%= f.submit "Upload" %>
<% end %>
In the Controller require csv, you do not need to install it as a gem but you do need to require it as it is in standard library not core.
require 'csv'
def my_method
@lines = []
CSV.parse(params[:submission][:file].read) do |row|
@lines << row
end
Replace the yellow bits with whatever you want to do with your CSV file.
Have fun!
What I wanted to do is accept a file from a form and parse it into a list of users to be added to the database without saving the CSV file. (Note: I DO save the file via the Paperclip Gem for logging purposes but I do all the processing from the file before it is saved to the database.)
When you have uploaded the file using Form_Tag, the file is usually in params[:name] where :name is tag you gave to file_field_tag :name
If you are using a Form_For, which by the way is strange if you do not intend to save it to the model in question, the file will be in params[:model][:name] from f.file_field :name
The magic part is to actually get to the file you need to call .read on it.
In the View remember to make it multipart to accept files.
<%= form_for @model, :html => { :multipart => true } do |f| %>
<%= f.label :file %><br />
<%= f.file_field :file %><br />
<%= f.submit "Upload" %>
<% end %>
In the Controller require csv, you do not need to install it as a gem but you do need to require it as it is in standard library not core.
require 'csv'
def my_method
@lines = []
CSV.parse(params[:submission][:file].read) do |row|
@lines << row
end
Replace the yellow bits with whatever you want to do with your CSV file.
Have fun!
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.
<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>
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>
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.
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/
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.scssThe 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>
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
"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.
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!
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.
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"
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.
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.
Sunday, 26 February 2012
Rails 3 on Ubuntu11.04 (11.10)
It seems that when asked how to install Rails on Ubuntu everyone immediately points to RVM and to be honest, there are many good reasons to. Just in case you don't want to use RVM for whatever reason and choose to walk the other path, there are plenty of pitfalls to consider there.
Things to note:
I'm starting with a new Ubuntu Server 11.04 on a VirtualBox (Edit:Version 11.10 as of 26/02/2012)
The only commands I've used before this is sudo apt-get install xinit and sudo apt-get install fluxbox but I am not running either of those packages while getting ruby or rails. I just like having a text editor and terminal up at the same time.
Edit: This also works exactly the same on Ubuntu Desktop x64 v11.10
Installing without RVM
Things to note:
I'm starting with a new Ubuntu Server 11.04 on a VirtualBox (Edit:Version 11.10 as of 26/02/2012)
The only commands I've used before this is sudo apt-get install xinit and sudo apt-get install fluxbox but I am not running either of those packages while getting ruby or rails. I just like having a text editor and terminal up at the same time.
Edit: This also works exactly the same on Ubuntu Desktop x64 v11.10
Installing without RVM
We are going to need the compilers included in build-essential in order to build native extensions of gems later.
sudo apt-get install build-essential
We are going to need sqlite3 also
sudo apt-get install sqlite3 libsqlite3-dev
We are going to need sqlite3 also
sudo apt-get install sqlite3 libsqlite3-dev
The name is ruby1.9.1 but this is 1.9.2, testable by using the ruby -v command after you have installed it. Also you must use the -dev version as the ruby1.9.1 does not include some dependencies needed to run itself due to the Debian packaging system (according to a Google search)
sudo apt-get install ruby1.9.1-dev
sudo gem install rails
Rails at this point will not run as we will not have a Javascript engine. TheRubyRacer is officially advised against by Heroku so lets go for Node.Js for now
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
You should now be adle to start a Rails app and run Rails server without Rails yelling at you about Javascript.
Now is the time to install any gems you like, lets go for RSpec and Cucumber and their Rails variants to start with.
sudo gem install Rspec
sudo gem install Cucumber
sudo gem install Rspec-Rails
Before we can install the cucumber-rails gem we need to make sure we have a couple more packages or we will experience strange errors.
sudo apt-get install libxslt-dev libxml2-dev
Now we can get Cucumber-Rails in peace
sudo gem install Cucumber-Rails
If there is anything missing please comment below so others can see it.
I will keep updating this post with any error messages that you can encounter along with their fixes so people can google their way here, in making this I ran into multiple errors that were unique or variants of other errors only.
~Greg Myers
~BookOfGreg
Rails at this point will not run as we will not have a Javascript engine. TheRubyRacer is officially advised against by Heroku so lets go for Node.Js for now
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
You should now be adle to start a Rails app and run Rails server without Rails yelling at you about Javascript.
Now is the time to install any gems you like, lets go for RSpec and Cucumber and their Rails variants to start with.
sudo gem install Rspec
sudo gem install Cucumber
sudo gem install Rspec-Rails
Before we can install the cucumber-rails gem we need to make sure we have a couple more packages or we will experience strange errors.
sudo apt-get install libxslt-dev libxml2-dev
Now we can get Cucumber-Rails in peace
sudo gem install Cucumber-Rails
If there is anything missing please comment below so others can see it.
I will keep updating this post with any error messages that you can encounter along with their fixes so people can google their way here, in making this I ran into multiple errors that were unique or variants of other errors only.
~Greg Myers
~BookOfGreg
Subscribe to:
Posts (Atom)