I am focusing on a task by which I am getting slight difficulties approaching using the design for any apparently quite simple scenario:

user goes to city which goes to country, however, the city reference might be null while user must fit in with a country nonetheless. Quite simply (in fundamental RoR model syntax),

# class User < ActiveRecord::Base 
belongs_to :city
belongs_to :country
validates_existence_of :country

# class City < ActiveRecord::Base
has_many :users
belongs_to :country
validates_existence_of :country

# class Country < ActiveRecord::Base
has_many :users
has_many :cities    

My trouble with this super simple design is always that there's a lot redundancy. The moment a city is recommended with a user, the country reference could be extrapolated from this (quite simply, as it is already recommended within the city table, it appears not-so-awesome also to reference it within the user table).

This is exactly what occurs when A (city) also distinctively identifies B (country), but A is optional while B is required. Essentially, Country is just added because City is optional while there's still a necessity to recognize the nation of every user.

The thought of tying country and city together, may appear attractive just because a city distinctively "identifies" a rustic, but: will it? Amsterdam isn't just a town within the Netherlands you realize.

And it also carries the issue you already pointed out inside your comment... where do you turn with a lot more data and listing nations as a result now requires blocking them from the country/city amalgamation.

Your original design may go through redundant and data-smart it most likely is, but logic-smart and requirement-smart it is not. I'd stick to it because it is very obvious and reflects the needs perfectly. And That I would learn how to accept the apparant redundancy. Any "solution" you might develop to prevent the "redundancy", will probably just finish up muddying the waters. Or can make determining queries later on harder.

It has the 'sql' tag for whatever reason, so here's how I'd get it done in SQL (note there's referential integiry throughout with no NULLable posts):

CREATE TABLE Countries 
(
 country_code CHAR(3) NOT NULL UNIQUE
);

CREATE TABLE Cities 
(
 city_name VARCHAR(20) NOT NULL, 
 country_code CHAR(3) NOT NULL 
    REFERENCES Countries (country_code), 
 UNIQUE (country_code, city_name)
);

CREATE TABLE Users
(
 username CHAR(8) NOT NULL UNIQUE, 
 country_code CHAR(3) NOT NULL, 
 UNIQUE (country_code, username)
);

CREATE TABLE UsersCountries
(
 username CHAR(8) NOT NULL UNIQUE, 
 country_code CHAR(3) NOT NULL, 
 FOREIGN KEY (country_code, username)
    REFERENCES Users (country_code, username), 
 city_name VARCHAR(20) NOT NULL, 
 FOREIGN KEY (country_code, city_name)
    REFERENCES Cities (country_code, city_name)
);

Test data:

INSERT INTO Countries (country_code) VALUES 
('ITL'), 
('ESP');

INSERT INTO Cities (city_name, country_code) 
VALUES 
('Roma', 'ITL'), 
('Naples', 'ITL'), 
('Barcelona', 'ESP'), 
('Madrid', 'ESP');

INSERT INTO Users (username, country_code) VALUES 
('00000001', 'ESP'), 
('00000002', 'ESP'), 
('00000003', 'ITL'), 
('00000004', 'ITL');

INSERT INTO UsersCountries (username, city_name, country_code) 
VALUES 
('00000002', 'Madrid', 'ESP'), 
('00000004', 'Roma', 'ITL');

To become fair, most SQL programmers won't have a strong dislike to presenting a NULLable column and can prefer all user's particulars to look in a single table. Presuming your SQL product (properly) doesn't treat NULL like a value (for instance MS SQL Server doesn't but MS Access does) then your following works and is the same as the above mentioned structure (i.e. again referential integiry throughout despite the presence of NULLable posts):

CREATE TABLE Users
(
 username CHAR(8) NOT NULL UNIQUE, 
 city_name VARCHAR(20), 
 country_code CHAR(3) NOT NULL
    REFERENCES Countries (country_code), 
 FOREIGN KEY (country_code, city_name)
    REFERENCES Cities (country_code, city_name)
);

INSERT INTO Users (username, city_name, country_code) VALUES 
('00000001', NULL, 'ESP'), 
('00000002', 'Madrid', 'ESP'), 
('00000003', NULL, 'ITL'), 
('00000004', 'Roma', 'ITL');