Changes:
June 30th, 2015
sshd_config
.service <COMMAND> <ACTION>
seems Ubuntu nowdays have problem with /etc/init.d
, it is old school, but I’ve liked it. (Thanks to Rapha for mention it in comments).2.2.2
January 9th, 2014
Here are notes and step-by-step tutorial to set Ubuntu VPS secure and with nginx, node.js, ruby, PostgreSQL, …
It should work for Ubuntu 12 or 13 or 14 versions. My VPS provider still doesn’t have support Ubuntu 15, but I don’t think that there would be any problem using this for Ubuntu 15.
It assumes knowledge of SSH and connecting to your fresh VPS install.
Throughout the install process for editing I’m using vi, you can use what ever makes you happy: emacs, nano, …
Those are just my notes, if someone has something better or can improve it please do comment!
sudo apt-get -y update
sudo apt-get -y install curl git-core python-software-properties software-properties-common
Very annoying error in apt: locale: Cannot set LC_CTYPE. It is probably due to your local machine, add this to your .bashrc
or .zshrc
:
export LANGUAGE=en_US.UTF-8
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
sudo groupadd admin
sudo adduser <USERNAME>
sudo usermod -a -G admin <USERNAME>
sudo dpkg-statoverride --update --add root admin 4750 /bin/su
Test new user and test that has sudo
privileges:
su <USERNAME>
Secure SSH:
sudo vi /etc/ssh/sshd_config
Make these changes:
Port
PermitRootLogin
no
X11Forwarding
no
AllowTcpForwarding
no
AllowUsers
USERNAME USERNAME2If your SSH is very slow setting X11Forwarding
to no
can really help in this case!
sudo service ssh restart
Connect to VPS SSH:
ssh <USERNAME>@<VPS_DOMAIN_OR_IP> -p <PORT>
The idea is to not permit passwords and use SSH keys for authentication, and some other tweaks to SSH.
mkdir ~/.ssh
vi ~/.ssh/authorized_keys
And paste the content of your local machine Public Key file: .ssh/id_rsa.pub
and make it rw
only for current user:
chmod 600 ~/.ssh/authorized_keys
Or use ssh-copy-id
from your local machine, which isn’t on Mac, and can be installed with brew
but I have no luck:
brew install ssh-copy-id
ssh-copy-id "<USERNAME>@<VPS_DOMAIN_OR_IP> -p <PORT>"
Try to connect to SSH and it should not ask you for password, it should be instant login:
ssh <USERNAME>@<VPS_DOMAIN_OR_IP> -p <PORT>
Open SSH config file, uncomment PasswordAuthentication
which is by default set to yes
:
sudo vi /etc/ssh/sshd_config
Change it to no
:
PasswordAuthentication no
Restart SSH and try to connect again:
sudo service ssh restart
Exit the VPS shell and try to connect to VPS SSH.
To have ping
and apt-get
working, add the following into iptables, as ufw just interfaces with it.
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo apt-get -y install ufw
sudo vi /etc/default/ufw
Make this change:
IPV6=no
Allow some ports and services:
sudo ufw allow <PORT_NUMBER_CHANGED_TO_SSH>
sudo ufw limit ssh
sudo ufw allow 80/tcp
sudo ufw allow out 53
sudo ufw logging on
Be sure that you allowed the changed port for SSH because otherwise, you’ll be unable to get into VPS!!!
sudo ufw enable
Check the Firewall status with:
sudo ufw status verbose
sudo mv /etc/sysctl.conf /etc/sysctl.conf.orig
sudo vi /etc/sysctl.conf
Add this to a sysctl.conf
:
# IP Spoofing protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# Ignore send redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Block SYN attacks
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# Log Martians
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# Ignore Directed pings
net.ipv4.icmp_echo_ignore_all = 1
Then run, there can be possible some errors, especially on VPS with OpenVZ…
sudo sysctl -p
Before Denyhost was uset but it seems it is no longer maintained and there is no Ubuntu package anymore so the Fail2Ban is alternative, but since the SSH is set to permit only SSH keys, both of those are redundant.
If for some reason you have completely unnecessary Samba installed by default on VPS you can remove it with:
sudo apt-get -y remove --purge samba
Same with Bind, if you don’t need it, remove it!
sudo apt-get -y remove --purge bind9
sudo rm -rf /var/cache/bind
sudo rm -rf /usr/share/bind9
sudo rm -rf /etc/bind
Check if ~/.ssh
has *.pub
files, if not generate the SSH key:
ssh-keygen -t rsa -C "<YOUR_EMAIL>"
Use default place to store: ~/.ssh
Do not use passphrase, unless you want to type every time you commit to GitHub. (Or anyone knows better way?).
cat ~/.ssh/id_rsa.pub
Copy the contents to clipboard.
Go to GitHub > Account Settings > SSH Keys.
Hit Add SSH Key
give title and in Key
paste public key from clipboard.
ssh git@github.com
eval `ssh-agent -s`
ssh-add -k
sudo add-apt-repository ppa:nginx/stable
sudo apt-get -y update
sudo apt-get -y install nginx
sudo service start nginx
If error is nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
then probably Apache is installed beforehand:
sudo apt-get remove apache2-mpm-prefork
sudo apt-get remove apache2-mpm-worker
sudo apt-get remove apache2
You can check and purge installed Apache:
sudo dpkg --get-selections | grep apache
# Purge others that are given as result from above command
sudo dpkg --purge apache2
sudo service nginx start
If something is wrong look for nginx logs:
sudo vi /var/log/nginx/error.log
sudo add-apt-repository ppa:pitti/postgresql
sudo apt-get -y update
sudo apt-get install -y postgresql libpq-dev
Log into postgres
change main password, create db user with password and create new database with previously created user as owner:
sudo -u postgres psql
\password "<PASSWORD>"
create user <USERNAME> with password '<USER_PASSWORD>';
create database <DB_NAME> owner <USERNAME>;
\q
sudo apt-get install mysql-server
The install will prompt you for root
user password that needs to be re-entered, choose password wisely and try to remember it! After install log into MySQL:
mysql -u root -p # After enter there is need to write password and hit enter again
Use mysql command line app for interacting with MySQL, lets create user and DB with user granted on this DB:
mysql> CREATE DATABASE <DB_NAME>;
mysql> SHOW DATABASES; # The new db should be listed.
mysql> CREATE USER '<DB_USERNAME>'@'localhost';
mysql> SELECT User,Host FROM mysql.user; # The new user should be listed on host localhost.
mysql> GRANT ALL ON <DB_NAME>.* to '<DB_USERNAME>'@'localhost' identified by '<DB_PASSWORD>'; # It will grant all on this DB by this user.
mysql> exit # Or new command \q
If you need to run SQL script for database, use this from command line:
mysql -u <DB_USERNAME> -p <DB_NAME> < <SCRIPT_NAME>.sql
cd
curl https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash
vi .bashrc
At top add:
export RBENV_ROOT="${HOME}/.rbenv"
if [ -d "${RBENV_ROOT}" ]; then
export P
ATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init -)"
fi
Reset .bashrc
:
. ~/.bashrc
Note that bootstrap-ubuntu-12-04
works fine for Ubuntu 13 & 14 (probably 15 too):
rbenv bootstrap-ubuntu-12-04
Firstly list rbenv available Ruby versions and pick one to install:
rbenv install -l
rbenv install 2.2.2
Set chosen Ruby version to be “global”, and test it:
rbenv global 2.2.2
ruby -v
The long list of PHP packages covering Imagemagick, MySQL, bcrypt,…:
sudo apt-get install imagemagick php5-fpm php5-mysql php5-curl php5-gd php5-intl php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-ming php5-ps php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl php5-xcache
Change usaul suspects of php.ini
properties:
sudo vi /etc/php5/fpm/php.ini
upload_max_filesize
= (SOME_NUMBER)M (Default 2Mb - safe to use 25M)post_max_size
= (SOME_NUMBER)M (Default 8Mb - safe to use 25M)memory_limit
= (SOME_NUMBER)M (Default 128Mb - safe to use 512M)Restart PHP-FPM and Nginx:
sudo pkill php5-fpm; service php5-fpm start
sudo service nginx restart
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get -y update
sudo apt-get install -y nodejs
sudo apt-get -y install redis-server
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.default
pidfile /var/run/redis-server.pid
logfile /var/log/redis-server.log
sudo apt-get -y install erlang-nox
curl http://apt.basho.com/gpg/basho.apt.key | sudo apt-key add -
sudo bash -c "echo deb http://apt.basho.com $(lsb_release -sc) main > /etc/apt/sources.list.d/basho.list"
If Ubuntu is not LTS instead of lsb_release -sc
use name of LTS, eg. Ubuntu 14.10 (Utopic) is not LTS use 14.04 codename trusty instead. Use this Wikipedia table to help with names for particular Ubuntu version(s).
sudo apt-get -y update
sudo apt-get -y install riak
sudo vi /etc/pam.d/common-session
Add at the end of file:
session required pam_limits.so
Update limits.conf
:
sudo vi /etc/security/limits.conf
# Add this to limits.conf
* soft nofile 65536
* hard nofile 65536
If accessing riak nodes via SSH:
sudo vi /etc/ssh/sshd_config
UseLogin yes
Reboot machine and test that limit of open files is 65536
with:
ulimit -a
> open files (-n) 65536
or with:
ulimit -n
Hope it helps, please give feedback and comments with any missing/wrong parts to this Ubunt VPS install, because I’m far from Linux guru, but appreciate secure and stable Linux machine!
]]>Are you geeky enough?
Surely you guessed it, this will not go without console application in Mac this is Terminal, and some of us may us better one iTerm2, either way you’ll need to know how to open it.
Easiest way is to use Spotlight just hit Cmd + Space
and write Terminal and here we go…
The other way is in your Finder Applications > Utilities > Terminal
. (Those who use iTerm2, I bet they know how to open it :D)
Before we start on, MAKE SURE that your USB stick, external HDD, has single name to it, or better yet without spaces in name! e.g. ”MyPrecious
” is fine, ”My Precious
” is not!
And what I mean by name is the label name that you get in Finder or Desktop when you plug your device, that is underneath the HDD icon, this is mostly set by manufacture, and if you know how to format on Windows, you can also set custom name!
In Terminal create /etc/fstab
with nano
, easier for most users, others can use vim
, emacs
… (it will ask you for your username password if you have it, write it, if not just hit enter):
1
|
|
When is created enter this content inside of /etc/fstab
, be sure that you know the name of your device:
In my case in image is Elements
, be sure to change below “device-name” to name you got, and there is no spaces in name!!!
1
|
|
When you finished entering content, use Ctrl + X
(it is lowercase x), it will prompt you to save it or not, enter y
, you’ll get another prompt to write to file, just hit enter.
And that’s essentially it, I will not even try to explain what we just did, it will melt brain for most users, just believe me… I know what I’m doing!
The only problem is now, when you plug your device, you’re not gonna get a icon on Desktop or Finder.
Mac stores its mounted devices in hidden folder /Volumes
, so while we have Terminal up and running, make symbolic link of it to the Desktop:
1
|
|
Afterwards unmount your device (right click on device icon and choose Eject
), sometimes is needed to reboot (restart) your Mac, so it is safe to do so!
Now on your Desktop, you’ll have a “folder” named Volumes
, and when you plug your NTFS device, go into this folder, and you’ll find there your device armed and ready!
If you want to save from some other application, when the dialog is open, got to Desktop > Volumes > [Name of Device]
and save it!
And best thing is, if you are in no need to have support for NTFS anymore, remove /etc/fstab
:
1
|
|
… and everything is as before and live happily ever after!
This is how you can have writable NTFS support on your Mac, totally for free, and for bonus feeling geeky :)
But nevertheless, if you want to buy the software that does it for you, sure, be my guest… nobody is geek!
]]>ArchLinux is not for everybody, if you want everything out-of-box, then probably Ubuntu, Mint, Fedora or like are for you. But for me, and I have Mac, I see no difference between Ubuntu and Mac. Because for both, out-of-box you’ll get a predefined UI, apps. I’m not going into discussion that most of this can be change in Ubuntu, but how much of them really change?
ArchLinux is completely opposite, the install is not really easy (for average PC user), nor GUI like, and after install you are left with bare minimal packages needed for OS to run and configure, and without GUI too.
This installation is not for Linux n00bs, some familiarity with console and Linux commands should be expected, because some of notes are really not in depth and there are thing assumed, like basic knowledge of vim
(or you can replace vim
with nano
).
This is all part of my learning ArchLinux, and then to dual boot it on my Mac with Mac OS X. And even though I really like Mac, I really have huge respect and likeness for Linux, and my minimalistic side was in real need of distribution like ArchLinux. Why ArchLinux?
Just look into their wiki, that much of content and expressiveness (sometimes maybe too much) it is really what it makes ArchLinux great, and second is the Arch User Repository (AUR) where you can search for packages, install and comment them (very helpful comments!).
Another strength is that ArchLinux has no release versions, it is rolling released distribution, and if you update weekly or monthly, you’ll always have latest versions of your applications and ArchLinux respectively. Another strength (that is for someone is weakness) is that mostly ArchLinux packages are latest stable releases of software, and even this can get you to dependency hell, in most cases, you’ll end up with latest software with all new features and bug fixes immediately, and not waiting for next version release of OS distribution.
Note:
I use Dvorak keyboard layout and it is throughout the installation, if you use
us
layout ignore all of it, but if you use some other layout e.g.hr
then replace wheredvorak
tohr
!
Choose x86_64
version.
Change to Dvorak
layout:
1
|
|
Ping google.com to see if there is Internet connection, if not run:
1
|
|
Update pacman
package manager repository:
1
|
|
Install vim
as a default editor for installation (even though you can use installed plain old vi
or nano
):
1
|
|
See what disk structure there is:
1
|
|
For MBR installation use cfdisk
:
1
|
|
Create new partition with choosing [ New ]
with 1024 Mb for boot
directory (not necessary!).
Make it bootable by choosing [ Bootable ]
.
Create new partition with choosing [ New ]
with rest of your disk space for root
folder.
Create filesystems:
1 2 |
|
Mount partitions and create boot
dir, for boot partition:
1 2 3 |
|
Change mirror for pacman
, I use anything in Germany, and paste to top of mirrorlist
:
1
|
|
Install base and devel system (this can take for while, so better choose good mirror to be fast as possible!):
1 2 |
|
Generate fstab
and check it:
1 2 |
|
Chroot to mnt
:
1
|
|
Create custom Keyboard Layout in vconsole.conf
, and and add keyboard map for Dvorak:
1 2 3 4 5 |
|
Update with pacman
and install vim
(again, omit if you’re using vi
or nano
):
1 2 |
|
Set up locale, for me uncomment en_US UTF-8
in locale.gen
:
1 2 |
|
Create locale.conf
and export locale:
1 2 |
|
Set Time Zone by linking to time zone info to localtime
:
1 2 3 4 5 6 7 |
|
Set Hardware Clock to UTC:
1
|
|
Set Hostname:
1
|
|
Configure Network:
1
|
|
Set root
password:
1
|
|
Create new user that will be sudo:
1
|
|
Install sudo
with pacman
:
1
|
|
Uncomment wheel
group from sudoers ”%wheel ALL=(ALL)
”, so that user just created can be sudo:
1
|
|
Set password to created user:
1
|
|
Since we use MBR not GPT lets install GRUB BIOS
bootloader:
1
|
|
Install and configure GRUB
to /dev/sda
:
1 2 |
|
Exit chroot
, unmount mounted partitions and reboot:
1 2 3 4 |
|
Install Yaourt from archlinuxfr, for easier interaction/installation from AUR.
Add archlinuxfr repository to /etc/pacman.conf
:
1 2 3 |
|
Update pacman
and install yaourt
:
1
|
|
Install X server:
1
|
|
Install mesa
for 3D support
1
|
|
Install Guest additions:
1 2 |
|
Create virtualbox.conf
in /etc/modules-load.d
1
|
|
Add modules guest and video to virtualbox.conf
:
1 2 3 |
|
Log or su
as created user.
Copy .xinitrc
and add following content:
1 2 3 4 5 6 |
|
We did setup for console now we need to set up for X:
1
|
|
Install xterm
, xclock
and lwm
:
1
|
|
Start X
1
|
|
This is a first part of ArchLinux covering installation, configuration and testing that X or GUI is functioning properly. Next part is installing and configuring Window Manager. And since the Gnome and KDE are most popular, we will not use them at all! Intention is to use Tiled Window Manager…
]]>This is what wiill do to improve TeamCity 7:
Note:
This is not blog post how to set up TeamCity, this is usually really straight forward thing to do. So in this blog post I assume that there is TeamCity project and at least one Build Configuration already created!
1 2 3 4 |
|
Note:
When build starts by Agent, it will be 1.0.1 and at the end it will change to 1.0.1.53e7986!
1 2 3 4 |
|
Note:
I didn’t test shell version, it should work, but maybe some tweaks are necessary!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
|
Note:
Sorry, no Linux or Mac shell version of this script.
Having short Git hash for a Revision in your versioning is very helpful and seven chars are mostly always enough to uniquely identify this release build with commit in your Git repository.
The amazon S3 upload + send email with developer commit deatails is not state of art Powershell script, it is very buggy and not that much flexible, but it can help a lot in communication with QA (or outside beta testers) and having release build version binary, right after Developer commit!
]]>1
|
|
1 2 3 |
|
By running Fast Export I got error message:
1
|
|
Essentially this means that Python does not know about Mercurial.
The fix for that would be to install Mercurial as a Python module. I’ve used easy_install
:
1
|
|
The next error was:
1
|
|
To fix it there was need to set Fast Export with parameter --force
.
Make sure you are in the Git repository that you want to convert to:
1
|
|
Run from it a Fast Export like this:
Note:
Assumes that the Fast Export in directory up and the
hg_repo
is the Mercurial repository directory from where you want to convert from!
1
|
|
After few moments, your Mercurial (hg) repository will be converted to Git one!
And aftrer the conversion is applied run the checkout:
1
|
|
Beware if you have a lots of branches, that pushing master
will only push master. To push evrything to the remote
use:
1
|
|
And now all commits and previous branches are converted to Git!
]]>Firstly we really want to add a proper Xcode and Objective-C .gitignore
file. Here is the
Gist link to one proper .gitingnore. Download and copy
it to the App root, before doing the first commit or use wget
as I did!
Since we didn’t create the Git repository when the Xcode was offering. We shall create
repository, add .gitignore
and create initial commit:
1 2 3 4 5 |
|
Note
I would recommend creating repository without Xcode help. Because it will create no
.gitignore
and by it will commit a lot of junk to repository.Folders like
xcuserdata
will change frequently and polluting your repository with not needed files and even more in teams, it can overwrite another developer’sxcuserdata
every time with not wanted user data from other developer!
The Xcode Organizer is where the Repositories can be viewed.
Note
If you had a Xcode open during the creation of repository through Terminal, reopen the the Xcode because it will not detect the repository in Organizer.
To open Organizer go to Window > Organizer
or with keyboard shortcut ⇧ ⌘ 2.
There should be a repository Casa:
To add the Github remote so that we can push the commits to it, we first need to create a Github repository, I’ve already created repository casa-app-xcode.
Let’s add this remote with Xcode:
Add Remote
circled plus button.casa-app-xcode
.https://github.com/xajler/casa-app-xcode
.Ignore the git username and password if you have Github SSH set up.
File > Source Control > Push...
.The commit is pushed to Githb.
From the main app delegate MIAppDelegate.m
we shall remove the generated comments and
commit it with Xcode:
MIAppDelegate.m
by removing commented code in methods.File > Source Control > Commit...
or use keyboard ⌥ ⌘ C.Commit 1 File
button.On commit it can be chosen to commit to branch with button Commit to Branch...
. Where
the branch can be chosen or even newly one created.
Alternatively branches can be created in Organizer Repositories by selecting wanted
repository and selecting Branches, and hitting Add Branch
button.
Anytime while coding the Version editor can be turned on to see changes with current HEAD
but also it is possible to change to past revisions.
Xcode Version editor is really nice and with visuals that helping in better understanding of the code changes.
As I said in last post Xcode 4 is great IDE, filled with lots of features. Respect to have Git as default Version control. The SVN is also supported, but who would want to use it in 21st Century. But in my opinion the Diff part is the greatest feature of it all!
But with all of this, I’m still not impressed with managing Git with IDE, and I will still be using my favorite iTerm2 to interact with Git and Github.
So we past the Xcode project creation (from ground up!) and in this post the Version Control as Git and creating remote to the Github.
In next Xcode post we will have an broad overview of Xcode support of Testing. What Testing Frameworks are available, which is the default Xcode Testing Framework.
Look for the BDD Testing Frameworks and picking one for more in depth examine of it. And also the available Mocking Frameworks and its usage.
]]>Universal
App. I’ll be going through creation of
the minimal as possible project setup for current stable version of Xcode 4.5.2 and iOS 6.
So first, what exactly is a Workspace, as I remember it was introduced with Xcode 4, and it is a simply a container for combining multiple projects if they are needed, if not only Project will due. But in our case, we know that we shall have multiple projects, so the Workspace is way to go.
Note
Maybe the desired workflow by Apple was first to create a Project and then if there is need for another project to bundle them into Workspace. But I wanted show the hierarchical structure of Xcode project, so on the top is a Workspace then Project.
Create it by:
File > New > Workspace...
or better with the keyboard key ⌃ ⌘ N.Casa
and save it to Casa folder already created.Casa.xcworkspace
.Geek Tip
For hard-core coders open Xcode and Workspace from Terminal with
open Casa.xcworkspace
.
The Xcode project is the thing that is usually what it is created in most examples. This way Project and the Target(s) will be created together.
But not to get the ahead of myself, we will not use this pattern, since we broke it with creation of Workspace in first place, we will broke it even more by creating empty project.
Because when you start with the Empty Project you can actually see what Project is, basically nothing, just another container, that will hold Targets.
File > New > Project...
or by keyboard shortcut ⇧ ⌘ N.Next
button, add Product Name, in my case, still Casa.Next
button, go to Casa folder, because we want the project to be created there.So finally we’re getting to the meat of Xcode, the Target is what will hold all you code, resources, settings for build or deployment. If we had not chosen Empty Project in last part, it would create Project and Target all together, even if we chose the Empty Application.
But we are learning all the parts so we shall in this case create a simple as possible Target for iOS - Empty Application.
Casa
Project is selected and at bottom hit a big plus button Add Target
.Next
.MI
as Metaintellect), because there is no namespacing in Objective-C
.Universal
(iPhone and iPad support).Finish
button and we have a target created.Project > Build
or with ⌘ B and we can ship it :)So there are many ways to get to AppStore and not using the default Apple language: Objective-C. One of many are RubyMotion (Ruby), MonoTouch (C#), PhoneGap (HTML, CSS, JS),…, but Objective-C is still used as preferred language.
There is a lot of criticism on Objective-C language, even though it is a C based language, like C++, Java and C#. But those are kind of similar language where transition is very easy, but transition to Objective-C is awkward, even more than to JavaScript. And this is mostly because Objective-C has a not only strong legacy in C (static and procedural part) but also in one of the underestimated language Smalltalk (dynamic and object or better message driven part).
And even though the Objective-C looks very awkward, but because it has a legacy from two great languages that are in my opinion pretty hard and crazy to merge, has my everlasting respect. And I find my self writing Objective-C better and with more joy than the Java or C#.
What I dislike about the Objective-C is that code snippets, examples found on web are mostly so poorly written, and same for most paid Video Tutorials. So much repetitive code, huge methods, copy-paste driven development everywhere, same as in most .NET (especially VB.NET), PHP, and also in Rails (excluding pure Ruby programmers) examples!
There is quite a lot resources how to create iOS apps but mainly focusing on the features like Table Views, MapKit, and so on. But it is really hard to find good source on Design Patterns, refactoring and best coding practices, or how to structure the iOS app into Groups (there are no Folders, files are all in root of Target).
But there are quite neat features in Objective-C features like protocols and categories. I also like the progress or evolution of Objective-C for embracing properties, ARC (Automatic Reference Counting), Blocks, GCD (Grand Central Dispatch) and new literals for Arrays, Dictionaries,…
And for the end abandoning the old GCC compiler and embracing and involving in creating LLVM compiler, much faster, and now with really great code inspection built in to Xcode…
And there is Xcode, the version 3 was too funky too me, especially separate Interface Builder and Apple old-school floating inspectors and controls all around the desktop.
Bet then came the version 4 and even though I really dislike the IDEs, must admit that it is to me the best IDE. Especially comparing to Eclipse and Visual Studio. Responsiveness is great, integration with Git (even though I still prefer using it by Terminal) and diff viewer is really what was expected of Apple, also StoryBoard and integrated Inerface Builder. Multi monitor friendly, assistant editor, help integrated, I think you get it, the best IDE I’ve worked! Don’t get me wrong there is still place for improvements but in my opinion Apple is on the right track.
In next post we’ll examine Xcode SCM (Source Control Management) capabilities using built-in support for Git. Also we’ll push this project to GitHub, examine Xcode Git Diffing and History.
]]>But first, we shall change a mistake from the post on creating Sign Up page, the password
fields in the View are set as normal text. We shall make sure that it is a password field!
Change the text_field
to password_field
in app/views/users/_form.html.haml
:
1 2 3 4 5 6 7 |
|
Now when the password fields are fixed, lets create a test to save a Valid User to the database.
Create a new context
for POST
in spec/requests/users_spec.rb
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
The test is pretty simple, we fill up the form with data, click ‘Sign Up’ button, and
expect to be redirected again to “Sign Up” page (in new post when we create a Login page
the create
action will be redirecting to it!) and we expect that the flash notice will show that
User is successfully saved.
The test should fail on the clicking the Sign Up button, because there is no create
action in UsersController
:
1 2 3 4 |
|
So to pass this test we need to add a create
method to the UsersController
:
1 2 3 4 5 6 7 8 |
|
First we storing a User to instance variable @user
from the data given in User Sign Up
Form as params[:user]
. Then we try to save it, and on success, we assign the flash notice
and redirect back to Sign Up Page.
The test should pass:
Finished in 1.37 seconds
11 examples, 0 failures
The happy path is working, now lets test all the possible ways the Sign Up might go wrong!
Lets first check password
s matching is working, by applying the two different passwords.
We shall crate the new context
inside POST /users
context
and call it ”not saving invalid user”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
After running test we shall get odd message that there is no View Template for create
.
1 2 3 4 5 |
|
We don’t need a new View Template but rather change the UserController
method create
to do something if the user is not saved. And when is not saved we shall flash an error message:
1 2 3 4 5 6 7 8 9 10 11 |
|
We are setting as a flash message from a User instance errors and getting first full_message
that will be set upon having problem saving user and in this case message will be
”Password doesn’t match confirmation”.
After applying the given code, the test should pass:
Finished in 1.54 seconds
12 examples, 0 failures
With this code applied we also satisfy the tests that are yet to come, but we still need
tests to prove that create
method is working and proper error messages are thrown to
guide the users of Application to resolve them!
We have three required fields:
email
password
full_name
Lets write three more test, they should all be green since the implementation is written to satisfy the previous test.
We will add them to the ”not saving invalid user” context
below the latest test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
So, in first test we test required Email, by sending blank one. In second the Passwords are blank and in third the Full Name is blank. And each test expect that meaningful messages are shown to the user of application!
And if all was OK then all tests should pass:
Finished in 1.79 seconds
15 examples, 0 failures
The saving User with entered existing email
should fail. Lets create the test to prove
it:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
So, first we insert User from our created factory via Factory Girl. The factory of User inserted has the same email that we try to save it from the User Sign Up Form. And again we test to get meaningful message when email is not unique.
The test should pass, because the code is implemented:
Finished in 2.02 seconds
16 examples, 0 failures
The User cannot be saved if both passwords length is at least 8 characters long:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
The test applies the Passwords that are of 3 characters long and we expect to get right message that is telling the right expectations of Password in this case minimum of 8 characters.
This was easy, all tests should pass still:
Finished in 2.07 seconds
17 examples, 0 failures
Note:
If you using Guard as I do, for running test, you may need to enter
r
command to Guard console to reload all, only if your tests are passing and they should not be or vice versa!
And with this test we have test for all User Create problems, now we’ll add test for User Update.
Essentially, the valid update only lets to change User password
and full_name
. Create
new context
called ”PUT users/:id” and new it
block ”valid user update”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
First we create a User from factory and save it as variable, because we are simulating edit,
so we need the User id when we want to edit him. This is why we pass the user
variable to the
edit_user_path
.
Before we fill in the User Update Form we shall test it if the Form fields are actually binded with data from User that will be updated.
OK, same thing as for new/create it will fail, first, because there is no method edit
in
UsersController
.
1 2 3 4 |
|
To pass this error lets create the edit
method:
1 2 3 |
|
So we need the User to get him from the given params id so that we can have it in
instance variable @user
and share it to the View and then fill the form with existing
User data.
The test should still fail, because there is no edit View Template:
1 2 3 4 5 |
|
Long time ago when we are creating View Template for Sign Up we’ve created new.html.haml
and also separated form to partial _form.html.haml
so it can be shared with Edit User View.
Lets create edit.html.haml
View page that calls the Form partial and passing to it the
@user
so that the Form will display User data:
1 2 3 |
|
The test will fail because there is no button “Update User”, and this is because we hard-coded
the “Sign Up” text to submit element in the form partial _form.html.haml
. We will fix it now,
not very pretty but it will work:
Change submit
in _form.html.haml
from:
1
|
|
To:
1
|
|
The test should still fail because we are after all trying to update, and there in no
update
method it UsersController
:
1 2 3 4 |
|
So, we shall impelment the update
method for the UsersController
:
1 2 3 4 5 6 7 8 |
|
First we getting User from the database from given User Id, and then call update_atrributes
from the data send via Form as params[:user]
. Set the flash notice that User is updated
and redirect to Update User page where we can see that User is actually updated.
And at last the test is passing:
Finished in 2.3 seconds
18 examples, 0 failures
The only problem here is that to Update User the password
s needed to be entered every
time. There are better solutions, like if they are blank, to ignore them on update, instead
currently it will be validated. And blank password is not allowed!
We will not try all the tests that we tried for User Sign Up, but only one. If you remember, this was the only test that was needed a code, others were just a proof of existing code, that is more about User Model than actual User View, but we’ve needed to run them all to ensure that flash messages are proper and expected.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
And the test fails, complaining about View, but actually we need the code in Controller, to send message of what went wrong to User Update Form:
1 2 3 4 5 6 7 8 9 10 11 |
|
After adding the else clause to update
method that handles all errors, the test
should pass:
Finished in 2.6 seconds
19 examples, 0 failures
The only test that is left is to ensure that email
given on create should never ever
be possible to change!
In this test we shall try to change the email of existing User and it needs to be the same
after update, even though the email
sent to update is quite different from the one when
User is created:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
The above test ensures that the email
after creation will stay intact, while other fields
will change, there will be no errors having different email
. The email
for update will
be silently ignored.
The implementation code of this validation is actually in User Model,
making the email
as attr_readonly
that we did in previous post, this test only ensures
that validation is implemented from View perspective.
And now all 20 test should pass, and we use RSpec format to show them all:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
The whole Users Controller app/controllers/users_controllers.rb
after this post should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
The whole Users Request Spec spec/requests/users_spec.rb
after this post should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
|
In this post we made sure that User Model Validation that is tested through actual User Sign Up and Update Views. And all aspects of Validation are tested in integration Broweser Tests simulated with Capybara.
In next post we shall finally tackle the Login page and implementing Authentication for Application.
The code is hosted on GitHub and can be cloned from the xajler/just-todo-it.
]]>Github xajler/just-todo-it commits for this post:
The User Create and Update Integration Tests, Users Controller and new Edit View Template.
A PUT tests are now top context, not child of POST context tests.
There are few rules that we’ve mention in last post about some validation logic:
We had one pending test up till now in spec/models/user_spec.rb
. We will use this test
file to set up the Validation for User in TDD way.
First remove pending part generated on User Model:
pending "add some examples to (or delete) #{__FILE__}"
First lets create a Factory of User that we’ll use in tests. This will be a valid Model of User:
1 2 3 4 5 6 7 8 |
|
Then we’ll learn some of RSpec and Factory Girl, but first add this beneath the describe
block:
1 2 3 4 5 6 7 |
|
RSpec let
description borrowed from the RSpec documentation:
Use let to define a memoized helper method. The value will be cached across multiple calls in the same example but not across examples.
Note that let is lazy-evaluated: it is not evaluated until the first time the method it defines is invoked. You can use let! to force the method’s invocation before each example.
RSpec subject
Use subject in the group scope to explicitly define the value that is returned by the subject method in the example scope.
There is also used a Factory Girl build
that returns a User instance that’s not saved, use create
if it is mandatory that Model is saved to database before getting it in tests.
The email
, password
and full_name
are required so we create the RSpec context
named
is invalid and even though we should go one by one test for each attribute, for quickness we’ll
do them at once:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Note:
The
#
is used to denote the Ruby way of describing the instance methods, the.
is used for the class methods!
The should_not
can be used since we set a subject
to be instance of User built from
Factory Girl :user
factory so the RSpec knows to what the should_not
refers to.
The be_valid
method is a RSpec shorthand for the Rails valid?
method that returns
boolean hence the ?
, every Ruby method with ?
can be called in RSpec with be_<name_of_method>
.
The running tests should failing with message:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
To make the test green, add the validates presence
for all three required properties
in the app/models/user.rb
:
1 2 3 4 5 6 7 8 9 |
|
The tests should all pass:
Finished in 0.81772 seconds
5 examples, 0 failures
Another validation for email
is that is need to be unique or there should not be two same
email
s stored in the database.
Add the new it
test to spec/models/user_spec.rb
in is invalid context
:
1 2 3 4 5 6 7 8 |
|
This test is little sketchy, firstly because there are two assertions and secondly of
saving our subject
User, then build
identical User, store him to user1
variable, and
then try to save User to database.
The second assertion is just to make sure that error is raised because of the email
uniqueness.
The failing message:
1 2 3 |
|
So the only thing is for us to prevent having email
stored to database more than once
with uniqueness
added to existing email vaildates
:
1
|
|
This should make the test green:
Finished in 0.8653 seconds
6 examples, 0 failures
Next there is need to make sure that the email
format is valid. The Regular Expression
is used to validate the email
format.
Note: There are better ways to do the complex Mail validation in Ruby or Rails, but it is out of scope of this simple app!
Add test below latest one, still in the is invalid context
:
1 2 3 4 |
|
The test should fail with message:
1 2 3 |
|
To fix it simple as possible add the format
to email validates
:
1 2 3 |
|
This should make to pass the test:
1 2 |
|
The User entered password
must be at least 8 characters.
The password
will also be simple as possible without checking that there are at least
one number or symbol, but rather, just to have at least 8 characters!
Add new test as last in context
is invalid:
1 2 3 4 |
|
The test should fail with message:
1 2 3 |
|
To make test pass add the length
to the password validates
:
1
|
|
The test should pass now:
Finished in 1.09 seconds
8 examples, 0 failures
The email
can only be set when is created and after saving to the database that email
must not ever be possible to change.
Outside of the context
is invalid create the new it
test:
1 2 3 4 5 |
|
This test is a little bit weird, what it ensures that when attributes are updated and
reloaded from the database, that the email
is still same as when it was created even
though is changed to new value.
The test should fail with message:
1 2 3 |
|
To make sure that email
is never changed after creation and all attempts to change the
email
will be silently ignored, use Rails attr_readonly
for email
.
Then the app/models/user.rb
should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
And the test should pass:
Finished in 1.28 seconds
9 examples, 0 failures
We tested all invalid combinations of the User to make sure that the logic we wanted is implemented, now for sanity check we’ll add the test to make sure when all given is valid then the User should be valid and saving of the User can be executed.
Add new test is valid
and the whole spec/models/user_spec.rb
should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|
And all 10 tests, Integration and Model should pass:
Finished in 1.24 seconds
10 examples, 0 failures
By default the RSpec tests are represented as dots (.
) if they are passed and F
if they fail.
To display describe
, context
and it
titles while running RSpec, add format
to
.rspec
file:
1 2 |
|
Run all test and the format of RSpec test should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
This post was all about the Rails Validation, there are few interesting samples how to test Rails application. The TDD in this post is solely done on User Model instead of on request browser based testes done with Capybara.
Now when we are sure that User Model validation logic is implemented and tested in next post, we will Save and Update User Views, Controller methods and create browser based test to make sure that User Model logic actually works in real usage!
The code is hosted on GitHub and can be cloned from the xajler/just-todo-it.
]]>Github xajler/just-todo-it commit for this post:
Implemented User Model validation and tested in user_spec.rb, the tests using users factory.
The User
Model will be very simple having only:
Note:
The first intention of this blog post was full User authentication, but since it uses TDD step-by-step development, and there is a lot from creating Route, Controller, Model and View this post will be only creating Sign Up page. Second and maybe third post will have validation, saving, authenticating and updating user!
First we will start with generating Rails integration_test
residing in spec/requests
folder:
1 2 3 |
|
First we will remove a GET /users
as describe
block generated by default in spec/requests/users_spec.rb
and left simple as:
1 2 3 4 |
|
In the users_spec.rb
we will add a context
block that will call the new
route and
expect to have fields for email
, password
, password_confirmation
, full_name
and button Sign Up
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
There are quite few asserts in this test, that is certainly not good practice in testing, but to make this post shorter, it is like this!
After running RSpec test or viewing from Guard
the expected error on saving file should be:
1 2 3 4 5 |
|
The problem is that there is no users route created.
Open config/routes.rb
, remove all commented code and add users
resource:
1 2 3 |
|
After run command to examine Rails routes:
1 2 3 4 5 6 7 8 |
|
You will see the new_user
path, but to actually get the path it is needed to be called
with _path
added to the route name as we called it in first test visit new_user_path
.
For this simple authentication we will only need creating and updating of user account, but in future, we may need, a full administration of users, including listing all and destroy them as well!
If there is a LoadError
after applying the route in Guard terminal:
1
|
|
Create a spec/routing
folder, to fix the issue:
1
|
|
After applying the user route (and Guard fix), there is a expected message complaining for existence of users controller.
To make test green, we need to create a user controller and the action or method called new
in the app/controllors/users_controller.rb
:
1 2 3 4 5 |
|
We are creating a new User
and setting it to a instance variable @user
, so it will be
visible within the View page!
The RSpec test will be failing since it doesn’t know what the User
is:
1 2 3 4 |
|
To make test green, we need to create a User
model in app/models
and it will have
email
, passmord_digest
and full_name
.
Having a password_digest
field is important as it’s the default name that’s used with Rails
has_secure_password
feature and we’ll be using this feature later.
Use this command to generate User:
1 2 3 4 5 6 7 8 |
|
Change the generate attr_accessible
to include email
, password
, password_confirmation
and full_name
needed for user create and edit form:
1 2 3 4 5 |
|
We also added has_secure_password
to the User model. This was introduced in Rails 3.1
and adds some simple authentication support to the model using that password_digest
column.
Note:
To have this
bcrypt-ruby
gem must be inGemfile
(we included it in first post) as this gem handles hashing the password before its stored in the database.
The generator will create a Model, Migration, RSpec test and a Factory Girl factory since we use it instead default Rails fixtures!
We will have another error regarding database:
1 2 3 4 |
|
To have a database and make green our test, run command:
1 2 3 4 5 |
|
Note:
This migration will create
development.sqlite3
SQLite 3 database indb
folder andusers
table.
We also need to prepare database for testing with:
1
|
|
Note:
This migration will create
test.sqlite3
SQLite 3 database indb
folder, andusers
table.
The RSpec test still will be failing with complaint on not having a view for user:
1 2 3 4 5 |
|
As we noted in first tutorial, instead of default Template View Engine erb
, we will use
far more better haml
View Engine.
But before using the haml
View Engine we need to convert default layout generated with
application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
to much more readable haml
default layout for application:
1 2 3 4 5 6 7 8 9 10 |
|
We need to create a view for user called new
, and it needs to have a fields for email
,
full_name
, password
, confirm password
and Sign Up
button.
Create a app/views/users/new.html.haml
:
1 2 3 |
|
Since the creating and updating User form will be identical, we shall create a partial
to reuse
user form on create and update views:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
And finally the test will be green, ignore for now that spec/models/user_spec.rb
is currently pending!
The beauty of it all, is that we didn’t even start browser, so we can do it now for test by running Rails server (Thin):
1 2 3 4 5 6 7 8 |
|
Open page:
http://localhost:3000/users/new
The design it is not really attractive at all, but it was not scope of the post, and should not be while creating application. When designers create full design it can be applied very easily. Functionality matters for now!
The /users/new
route name is descriptive but having just /signup
, I think is far more
better route name!
Create a new test context in spec/resources/users_spec.rb
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
The GET /signup
context is added that is now visiting the signup_path
!
Test fails:
1 2 3 4 |
|
There is no signup_path
so we need to create it in routes
:
1 2 3 4 |
|
The test passes and it is green, you can now try testing it in browser:
localhost:3000/signup
It should work just fine!
This post intended to absorb whole authentication of user, but currently is just too long and I will stop here and in second post will introduce validation, saving and maybe yet in third post authenticating and updating user!
The code is hosted on GitHub and can be cloned from the xajler/just-todo-it.
]]>Github xajler/just-todo-it commit for this post:
The app will be called Just ToDo it, just as famous
Nike slogan. And also Gods of DNS where
good to me so the Domain justtodoit.com
is free so I bought it and the final stage of this
Rails posts will be deployment to VPS and pointing to the domain JustToDoIt
(Currently displays my domain metaintellect).
The command to create new Rails application and omitting default testing framework Unit::Test
with switch -T
or longer version is --skip-test-unit
1 2 3 4 5 6 7 8 9 |
|
I had capitalized JustToDoIt
before, because the name is used as Ruby class and Pascal case is convention
for Ruby classes.
Then rename folder to just-todo-it
to be more in *nix folder naming convention:
1
|
|
The fun starts when the directory is changed to Rails app directory:
1
|
|
I’ll use vim as a default text editor, for TextMate use mate
and for the Sublime Text 2 use
subl
terminal commands for editing files instead of vim
.
First open the Gemfile
, we need to add some gems that will be used in the app and also
for testing:
1
|
|
Edit it to include this gems:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
After changing the Gemfile
run bundler to update and download entered gems:
1
|
|
3.2.8
for this time of writing.irb
. Needs some configuration to be hooked as rails console
.RSpec will be used as the test framework for the Just ToDo it
app.
Run generator to install RSpec to Rails:
1 2 3 4 |
|
1 2 3 |
|
Configure Guardfile
set the Spork on top and RSpec in bottom:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Bootstrap the Spork:
1 2 3 4 |
|
Edit RSpec helper:
1
|
|
And edit to include this content:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
It uses Spork server and the aim is to have most things in prefork
block where is
stuff run on load of Spork.
In each_run
block we want put only necessary things, because it runs each time,
we are now having only reloading of Factory Girl factories, but maybe we will add something
from prefork
if we would have some troubles with testing data.
DatabaseCleaner is used to start, on before and clean it, on after running. The strategy used for DatabaseCleaner is transaction, meaning to rollback changes after the transaction queries are finished.
The testing environment is now configured, the Guard can be run:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
or use bundle exec guard
to remove displayed warning.
To exit or stop the guard
command use Ctrl+C
.
And for the end we will set Pry as our default Interactive Ruby console.
Open the development.rb
:
1
|
|
At the end of source file add code:
1 2 3 4 |
|
Try it out with .pwd
and close the Pry with exit
command:
1 2 3 4 5 |
|
First remove the README.rdoc
file and create markdown README.md
:
1 2 |
|
Add simple description:
1
|
|
Initialize the git repository:
1 2 |
|
See the status:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Then add all files:
1 2 3 4 5 6 7 8 9 10 |
|
Commit the files to local repository:
1 2 3 4 5 6 |
|
The app will be on Github. So after the new repository is created on Github, we can add remote to the local repository:
1
|
|
After we add remote, it is now safe to push changes to Github remote repository:
1 2 3 4 5 6 7 8 9 |
|
It this first part we have created a JustToDoIt
Rails application.
And because we shall use TDD (Test Driven Development) to drive this app, we first configure the testing environment including:
And for the end we setup the Pry to be a default for Rails console and commit the source to the Github repository xajler/just-todo-it.
In second post we shall go with the creating the app logic in TDD way!
The code is hosted on GitHub and can be cloned from the xajler/just-todo-it.
]]>Github xajler/just-todo-it commit for this post:
Initial Commit. Created initial Rails app, added all needed Gems, testing configured
rake new_post
doesn’t generate Meta description and the keywords. The other problem is
redirect to single page which is broken since there is learnaholic.me and www.learnaholic.me
which can affect site ranking.
The third problem is that Octopress by default has a <domain>/blog
route path which is awkward
and unnecessary, domain is sufficient enough without /blog
.
The most SEO fixes are from the SEO for Octopress,Heroku post by Yatish Mehta.
The provided keywords and description should be a goal for each page, the problem is
that rake new_post
doesn’t generate keywords and description, so it should be added
manually.
I’ve added the keywords and description to all my posts created in this few days and the post Octopress metadata looks like this:
1 2 3 4 5 6 7 8 9 |
|
The Octopress by default shows latest post as home page, I choose not to go this way, my default home page is archive list. So there is no post from where it should include the keywords and description.
Open the _config.yml
and add the kewords and description keys:
1 2 |
|
In .themes/classic/source/_includes/head.html
after meta tag for author
replace the
current description/keywords code with this one:
To make sure that there is no differnce between learnaholic.me and www.learnaholic.me request, we shall include rewriting with gem rack-rewrite.
To Octopress Gemfile add:
1
|
|
To top of config.ru
(before SinatraStaticServer
) add:
1 2 3 4 5 6 7 8 9 10 |
|
Don’t forget to add a require on the top of the config.ru
:
1
|
|
Complete config.ru
should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
The Octopres by defult has a weird <domain>/blog/2012/10… route path, the blog
part of URL is totally unnecessary, so I removed it all together.
In _config.yml
change:
1 2 |
|
to:
1 2 |
|
Now the url should look like this:
http://learnaholic.me/2012/10/15/octopress-seo-and-disabling-the-blog-route/
But by default it would be:
http://learnaholic.me/blog/2012/10/15/octopress-seo-and-disabling-the-blog-route/
Improved SEO of the Octopress site:
The cleaner site path by removing the unnecessary /blog
from the URL route.
The things missing in Powershell:
Ctrl+a
,Ctrl+e
,…).Documents\WindowsPowerShell
(WTF).Maybe to most Windows users this is strange because this kind of stuff is never used, but if you’re coming from Linux or Mac then the frustration is certain. Because Linux or Mac are having great Terminal and working in them is just a joy.
The aim of post is to install git on Windowns and then configure it. Then customize a little bit the Powershell because the defaults are just crime against humanity. Configure SSH on machine and register SSH key with Github. Install must-have posh-git that will add the branch/status to Powershell prompt plus auto-completion for git.
Note that I’m using Windows 8 and Powershell version 3.0.
For those who might don’t know the git is created by Linus Torvalds the creator of Linux Kernel. Git was a product of his frustration maintaining Linux Kernel. He is not really the huge fan of Windows (nor am I) so git Windows implementation was hard to do because it really relies on Unix/Linux commands and philosophies that are lacking on Windows.
I know there was a problem I while back with the official Git version for Windows and I was always using the msysgit, don’t know if still is the case but I will use msysgit in this post.
Download the latest msysgit and install it with just clicking next few times. There are few things to configure, but using defaults is safest way.
Note:
There is also a Github for Windows. Probably even easier way to install and configure git on Windows, but I like to complicate things.
By default the git binaries are not set in to PATH, so add it by going to:
Control Panel/System and Security/System/Advanced system settings
Then in System Properties click on Environment Variables… and in System Variables list box
scroll to Variable Path
, double-click it and add at the end:
;C:\Program Files (x86)\Git\cmd;C:\Program Files (x86)\Git\bin;
Test that the git is available by opening the Powershell. Easiest way to open te Powershell
(if there is no shortcut) especially in Windows 8 is Win+r
and type powershell
to prompt.
In Powershell type:
1 2 3 4 5 6 7 8 |
|
If you get something like usage: git, then the git is ready!
Set the user name that will be readable in git log or history:
1
|
|
Then set your email:
1
|
|
Note:
Your email address for Git should be the same one associated with your GitHub account.
With msysgit comes a Git Bash needed to generate SSH keys. If you have one skip this step!
To open Git Bash right-click on any folder in Windows Explorer and choose Git Bash. In Git Bash enter:
1 2 3 |
|
Keygen will ask you for passphrase. In my first attempt I’ve added one, but on each commit I have to enter passphrase. That is so annoying.
If you have a SSH key passphrase and it annoys you then enter:
1
|
|
It will ask you for current passphrase, enter the current passphrasse, and with two enters, you’ll now have a blank passphrase!
The copy/paste is so awful in Git Bash. To paste you need to click the icon in top left corner,
go to Edit
then Paste
.
The copy is even more cumbersome, I’ll just give you a hint, choose Select All
!
Or read at the end in Options Tab part of Powershell Customization to enable QuickEdit Mode.
To set the public SSH key in Github there is need for getting it from a
~/.ssh/id_rsa.pub
.
Again open Git Bash right-click on any folder in Windows Explorer and choose Git Bash. In Git Bash enter:
1
|
|
This command will copy your public SSH key to clipboard. Then go to
Github / Account Settngs / SSH Keys and click the button
Add SSH Key
.
Enter Title (sorry about my title):
win-shit
Enter Key:
Just paste from clipboard
By clicking Add Key
you have successfully added SSH key to Github and
the git pushing to Github is now super easy.
The visual features of Powershell probably didn’t change since Windows 95, and defaults are probably still dating from ‘95 and selecting, copy, pasting is awkward, hard and unusable!
Click the small Powershell icon in top left corner, and in the context menu click on Properties
.
In Edit Options
check the QuickEdit Mode
. Quick edit mode enables selecting text from
anywhere in Powershell and with right-click it will copy the selected content.
Also with single right-click pastes the text where the blinking cursor
currently is, similar to putty.
This option really boosts the productivity in Powershell, it is too bad that this is not set by default!
Even we are in 21st century but the Powershell is still set by default to Raster Fonts
with
awkward sizes like 16x12, 6x8, that I never really get the meaning of.
In Font
list choose the Consolas font (or other available mono-space font) and you can check the
Bold fonts
if you like to have bold text. As for Size
in list choose whatever you want
I’ll stick to 18
.
The Powershell by default is very small, at least to me, maximize is totally unusable, there is no full screen!
Screen Buffer Size
and Window Position
Width height should be same size if you dont want
to have ugly horizontal scroll bar. I set Width to 125
and Window Position
Height to 35
.
This are all customization, it is not too much but Powershell suck a little less after it, but there is a room for lots and lots of improvements, while Microsoft spends time on useless technologies like Light Switch.
A set of Powershell scripts which provide Git/PowerShell integration. Includes:
Clone it from Github to any folder, I’ll clone it in source
folder:
1
|
|
Verify execution of Powershell scripts is allowed with:
1
|
|
The result should be RemoteSigned or Unrestricted.
If scripts are not enabled, run Powershell as Administrator and call:
1
|
|
Then cd
to posh-git
folder and run:
1 2 3 4 5 6 7 |
|
Then reload your profile, as noted in posh-git after install note:
1
|
|
If you’re done everything from this post then everything should work just fine!
The outcome of whole post is to have something at the end of the day:
And just for comparison the Terminal iTerm2 on my Mac OS X Mountain Lion with zsh shell and very short aliases, pure awesomeness:
]]>So far I was on this blog engines, chronologically:
So far I was always coming back to WordPress, but I was never actually satisfied in writing posts in it, everything other than that is plain perfect on WordPress. This is why I haven’t blogging for nearly two years.
Nowdays I really like markdown or any similar kind of markup language (textile, creole,…), and I would prefer writing blog posts with markdown. In my case blog posts are more notes than the blog posts, because they are more technical, and there is lots of code snippets!
Octopress is the very easy framework on top of Jekyll, and Jekyll is a blog-aware, static site generator in Ruby.
The official Octopress install is just to clone or fork the Octopress repo. I’ve chose to do fork then clone it from my forked repo.
1
|
|
Notes:
You’ll need to change the clone to your repository, since there is need for Read+Write access!
I’m lying a bit the first attempt was a clone, but afterwards I’ve chose to fork it, why?, you’ll need to read about it a little bit later.
The Octopress uses Jim Weirich’s great make-like build utility Rake, for creating posts/pages, deploying, generating,…
The Octopress needs for the first time to generate the sandbox with theme and placeholder folder for posts. It can be achieved by running (needs to be in forked/cloned directory):
1 2 3 4 5 6 7 8 |
|
The command will create source
and sass
folders. The source/_posts
folder is where the markdown
posts will reside.
This is why I forked the Octopress, so that I can commit the posts as the markdown files, if I would clone it, I should have the write access to Octopress, to commit, this way I have my forked version and still I can always pull changes from upsteramed original Octopress, but more of this in separate post.
Create post with new_post['post name here']
:
1 2 3 |
|
By opening it in your favorite editor you’ll get:
1 2 3 4 5 6 7 |
|
Categories can be add in few ways, my way is one-liner:
categories: [octopress, github, github pages]
Add some content to your first post and then run generate
command that generates whole site:
1 2 3 4 5 6 7 |
|
To locally preview generated Site use:
1 2 3 4 5 6 7 8 |
|
Then in browser navigate to:
http://localhost:4000/
The beauty of the preview
is that Auto-regenerating is enabled by default.
Meaning every save of blog post file will trigger generate
command making it as live preview.
The Octopress configuration is in the root _config.yml
file.
There you can change url
, title
, subtitle
, permalink
, twitter account
, github account
,
and set site comments via disqus by providing disqus_short_name
.
Octopress supports Heroku, rsync and Github Pages deployment. I chose the Github Pages because Github provide the CNAME changes, so the site can be on your desired domain.
There are two ways of having pages on the Github.
The User/Organization pages http://username.github.com
and project pages gh-pages
.
The my way was the User/Organization pages.
Create new repository on Github and named it as your User/Organization name plus .github.com
in my case was xajler.github.com
.
To prepare Octopress for deployment to Github Pages
run commannd and write Repository url
(git@github.com:xajler/xajler.github.com
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
This command will change git remote origin
from Octopress forked/cloned url to:
git@github.com:xajler/xajler.github.com
And also add a _deploy
folder, actual root of your Github Pages repository
(github.com/xajler/xajler.github.com
).
The final rake
command is deploy
. It will create commit and push to Github
repo and you’ll get notification to your mail.
1 2 3 4 5 6 7 8 9 10 |
|
After deployment in your mail box will be a notification:
[xajler.github.com] Page build successful
Your page has been built. If this is the first time you've pushed, it may take a few minutes to appear, otherwise your changes should appear immediately.
And if you navigate to http://xajler.github.com
(change xajler to your User/Organization name)
you’ll see the post and site online!
The http://xajler.github.com
is not really the URL that you’ll want to have for the blog.
Github provides the way to customize the domain name.
To setup the custom domain name that will point to your Github pages, there is need to
create the CNAME
file in source
folder. This CNAME
will be copied to _deploy
folder
when executing rake deploy
and will be used by Github to point to the provided domain.
1
|
|
I’ve added my subdomain for my domain metaintellect.
blog.metaintellect.com
Deploy with rake deploy
and it should now be pushed and visible in your
Github repo (xajler.github.com
).
The DNS nameservers for my domain metaintellect are declared on dynadot.
Here is my configuration to make the blog.metaintellect.com
CNAME work with Github Pages:
I hope that I will now blog my notes about so many tehnical IT stuff I do everyday, and now with markdown and the Github it is fairly easy and fun!
]]>A few months ago I’ve created a simple Rails app (after 6 years!!!) that essentially stores guests and keeping track of accommodations for my friend’s villa.
After a month in production I’ve started thinking about backup of the database. Code is on the Github so I have only need to worry about database.
My first initial thoughts were on Dropbox, I’ve installed the Dropbox client on my no GUI Ubuntu Server, but when I ran the Dropbox the memory usage got doubled and I remove it all together!
Then I started thinking about good old FTP backup, I was sure that I want backup somewhere else than the VPS where the database is running. I have one account at Arvixe, Unlimited Linux hosting and I’ve created the FTP user and even found this backup gem back then but I just drop all together until today.
I have VPS at BuyVM (ex Frantech) and they are offering a free storage VPS of 5Gb which is more than enough for my backup. I signed for an account and idea came again to use it as backup…
…and the idea expanded to include every day schedule of backup.
Incidentally, to day I finally get started my Octopress blog deployed via Github Pages, so I’m writting all the steps as notes for futre usage, or if someone can be useful…
The backup gem is one great gem with a lot of backup options like databases, storages, compressions, encrypt-ors,…
Installation is a straight forward like any Ruby Gem:
1
|
|
backup gem have its own backup “model” generator that creates backup config files, this is a comprehensive usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Let’s create simple config file with backup generator:
1 2 |
|
This will create a config.rb
and models/miguest_backup.rb
files in ~/Backup
folder.
Backup generator will create boilerplate model template needing more refinement. It looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
Fairly straight forward refinements are needed, usernames, passwords,… After adding all the secret stuff, the backup can be run as easy as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
And after the connecting to the storage server via FTP, there is backup:
Really, what I’m using for backup is just minimal what backup gem can offer, here is detailed impressive list of backup features:
MySQL, PostgreSQL, MongoDB, Redis, Riak
bzip2, gzip, lzma, pbzip2
cloudfiles, Dropbox, FTP, local, ninefold, rsync, S3, scp, SFTP
campfire, hipchat, mail, presently, prowl, twitter
GPG, OpenSSL
Whenever is a Ruby gem that provides a clear syntax for writing and deploying cron jobs. And this is what I need to schedule the backups to run everyday.
1
|
|
Configure the whenever, but first make sure that we are in backup folder ~/Backup
1
|
|
Then create config folder:
1
|
|
And then run the command:
1 2 3 |
|
Open the config/schedule.rb
file and add the following:
1 2 3 |
|
Run whenever
with no arguments see the crontab
entry this will create:
1 2 3 4 5 |
|
To write (or update) this job in your crontab
, use:
1 2 |
|
And that’s it, so what is included:
The scheduled backups are working and here is the picture as proof!
Note that servers are not in same Time Zone hence offset of two hours. I know that one is in Chicago, and second is in California or New York, but either way the scheduled backup works!
]]>Use brew
to install the nginx
with command:
1
|
|
After install run:
1
|
|
Test it by going to URL:
http://localhost:8080
The default place of nginx.conf
on Mac after installing with brew
is:
/usr/local/etc/nginx/nginx.conf
The nginx default port is 8080, we shall change it to 80. First stop the nginx server if it is running by:
1
|
|
Then open nginx.conf
with:
1
|
|
and change the:
1 2 3 4 5 6 7 8 9 10 |
|
to:
1 2 3 4 5 6 7 8 9 10 |
|
Save configuration and start nginx by
1
|
|
The nginx html folder (brew install only) is by the defult in:
/usr/local/Cellar/nginx/1.2.3/html
Note: change 1.2.3
to your nginx version.
The defualt path configuration:
1 2 3 4 5 6 7 8 9 10 |
|
To let say Users/xajler/www
:
1 2 3 4 5 6 7 8 9 10 |
|
After change stop and start nginix server and nginx is now serving pages from your custom folder!
]]>