Find all records associated with an ActiveRecord::Base model

If you are too lazy to look up the source file, just hit this up in the rails console.

1
2
3
4
5
InterestingModel.reflect_on_all_associations.map{ |assoc| [assoc.macro, assoc.name] }
# =>[[:belongs_to, :foo_model],
# [:has_one, :bar_model],
# [:has_one, :other_model]
#=> ActiveRecord::Reflection::AssociationReflection

Addtion:
You can also see all associations for an instance of a model.

1
2
InterestingModel.new.reflections
#=> ActiveRecord::Reflection::AssociationReflection

This also works with Classes themself

1
2
InterestingModel.reflections
#=> ActiveRecord::Reflection::AssociationReflection

Note that reflect_on_all_associations returns an Array of all Associations and
reflections will return a Hash like { :association_name => ActiveRecord::Relfection::AssociationReflection }

When struggling with postgresql and utf8/latin

This is just a little information dump for me, you probably won’t have these issues.

Lately I tried to switch the database in a Rails app from SQLite to PostgreSQL.
However, after installing postgres and setting up my database.yml file on my vagrant ubuntu(precise32) box, I fire

1
rake db:create

and it greets me with

1
2
3
4
5
Couldn't create database for {"adapter"=>"postgresql", "encoding"=>"unicode", 
"database"=>"stuff_development", "pool"=>5, "username"=>"stuffer", "password"=>nil}
PG::Error: ERROR: encoding "UTF8" does not match locale "en_US"
DETAIL: The chosen LC_CTYPE setting requires encoding "LATIN1".
: CREATE DATABASE "stuff_test" ENCODING = 'unicode'

There are some encoding issues, yeah!
After some googeling I tried the solution provided by this post which unfortunatly ended up with this:

1
2
3
postgres=# create database template1 with owner=postgres template=template0 encoding='UTF8';
ERROR: encoding "UTF8" does not match locale "en_US"
DETAIL: The chosen LC_CTYPE setting requires encoding "LATIN1".

But adding some additional options did the trick

1
2
create database template1 with owner postgres encoding='UTF-8' 
lc_collate='en_US.utf8' lc_ctype='en_US.utf8' template template0;

In summary, when you get such errors try these steps

1
2
sudo su postgres
psql
1
2
3
4
5
update pg_database set datistemplate=false where datname='template1';
drop database Template1;
create database template1 with owner=postgres encoding='UTF-8'
lc_collate='en_US.utf8' lc_ctype='en_US.utf8' template template0;

update pg_database set datistemplate=true where datname='template1';

Get recipes from chefkoch.de using ruby | Part 2

Even it’s quite a while ago since part 1, I want to finish up this micro series about the chefkoch api.
As you may remember, we are able to search for recipes, whose titles are matching our search string.
Unfortunatly, the api response is not serving any link to the recipe itself.
So let’s fix this and add this url directly to our method’s result!

First we need to find out, how the recipe urls are built.
By checking some recipes on their site, we can see that recipe urls are built like that:

1
2

http://www.chefkoch.de/rezepte/:id

Now we could extend our search method by telling it to call a method named “append_recipe_link” and passing our response to that method:

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
require 'net/http'
require 'json'
require 'uri'

module ChefkochApi
@api_url = "http://api.chefkoch.de/api/1.0/api-recipe-search.php"
@rezept_url = "http://www.chefkoch.de/rezepte/" # this is new

def self.search(search_text)
# ... stil the same stuff
response = Net::HTTP.get_response(url)

self.append_recipe_link response
end

private

# our new helper method
def self.append_recipe_link(response)
# here comes some JSON magic to extract only the relevant information from the json response
JSON.parse(response.body.strip)["result"].each do |r|
r["RezeptUrl"] = @rezept_url + r["RezeptShowID"]
end
end
end

And there you go. Your results should now have a url linking directly to the recipe show page.

The last thing I want to show is, how you get more detailed information about your recipes.
I am using another method for that, which does another api call. Please note the aditional api url at the top.

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

require 'net/http'
require 'json'
require 'uri'

module ChefkochApi
@api_url = "http://api.chefkoch.de/api/1.0/api-recipe-search.php"
@api_rezept_url = "http://api.chefkoch.de/api/1.0/api-recipe.php"
@rezept_url = "http://www.chefkoch.de/rezepte/"

def self.search(search_text)
# ...
end

# here we go
def self.show_recipe(id)
# Remember "RezeptShowID" from our JSON response?
# Thats the id which gets passed to this method here
params = {}
params["ID"] = id

url = URI.parse @api_rezept_url
url.query = URI.encode_www_form(params)

response = Net::HTTP.get_response(url)
JSON.parse(response.body.strip)["result"]
end

private

def self.append_recipe_link(response)
# ...
end
end

This gives us more detailed information about a recipe in response:

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
{
"api":{
"version":1.2
},
"total":1,
"result":[
{
"rezept_id":"101077",
"rezept_show_id":"1010771206206427",
"rezept_name":"Apple Pie",
"rezept_name2":"",
"rezept_zubereitung":"Mehl, Butter, Zucker, Zitronenschale (oder wahlweise eine Packung Citroback), Salz und die Eigelbe mischen und zu einem Teig verkneten. \r\n\r\nDie \u00c4pfel sch\u00e4len und in St\u00fccke schneiden, mit etwas Zucker und Wasser in einem Topf 5 min. kochen lassen (nach Geschmack noch ein wenig zerdr\u00fccken), die Masse abk\u00fchlen lassen. \r\n\r\nDen Teig in zwei St\u00fccke teilen. Den gr\u00f6\u00dferen Teil ausrollen und die Form (ca 20 cm Durchmesser) damit auslegen. Nun die abgek\u00fchlte Masse auf dem Teig verteilen. Den Rest des Teiges ausrollen und oben auf die Apfelmasse legen. An den Seiten andr\u00fccken. Das Ganze wird nun mit einem Eigelb (gemischt mit etwas Wasser) bestrichen.\r\n\r\nDas Ganze im vorgeheizten Ofen bei 180\u00b0C 45 \u0096 50 min. backen lassen. Am besten noch warm genie\u00dfen.",
"rezept_portionen":"1",
"rezept_preparation_time":45,
"rezept_cooking_time":0,
"rezept_resting_time":60,
"rezept_schwierigkeit":"simpel",
"rezept_kcal":"0",
"rezept_user_id":"3733fd403a13fb5f951c2369ae1acd22",
"rezept_user_name":"KaThePrincess",
"rezept_datum":"1206640697",
"rezept_videos":[

],
"rezept_in_rezeptsammlung":[
{
"sammlungs_id":"946538",
"sammlungs_name":"Apfelkuchen",
"sammlungs_link":"\/rezeptsammlung\/946538\/Apfelkuchen.html"
},
{
"sammlungs_id":"1803978",
"sammlungs_name":"Kuchen und andere s\u00fc\u00dfe sachen",
"sammlungs_link":"\/rezeptsammlung\/1803978\/Kuchen-und-andere-suesse-sachen.html"
}
],
"rezeptsammlungen_link":"\/rezeptsammlung\/0,30\/1010771206206427\/",
"rezept_zutaten_is_basic":[
"71",
"70",
"83",
"6",
"247"
],
"rezept_zutaten":[
{
"id":"71",
"name":"Mehl",
"eigenschaft":"",
"cominfo":"0",
"ist_basic":"1",
"menge":"225",
"einheit":"g",
"menge_berechnet":225,
"has_additional_info":false
},
{
"id":"70",
"name":"Butter",
"eigenschaft":"",
"cominfo":"0",
"ist_basic":"1",
"menge":"140",
"einheit":"g",
"menge_berechnet":140,
"has_additional_info":false
},

and so on and so on ...

],
"rezept_tags":[
"Backen",
"Kuchen",
"USA oder Kanada",
"Weihnachten"
],
"rezept_user_portionen":"1",
"rezept_votes":{
"average":3.3333,
"img":"3_5",
"votes":"1",
"result":"5"
},
"rezept_statistik":{
"total":{
"viewed":"4095",
"saved":"12",
"printed":"71",
"mailed":"1"
},
"month":{
"viewed":"16",
"saved":"0",
"printed":"1",
"mailed":"0"
}
},
"rezept_frontend_url":"http:\/\/www.chefkoch.de\/rezepte\/1010771206206427\/Apple-Pie.html"
}
]
}

Now our module has quite some functionality. Hope this was usefull for at least a few people.