You mean like this?
> library(dplyr)
> library(tidyr)
> group_by(df,id,age) %>% gather(variable,value,age,edu) %>% 
    unite(tag,variable,value) %>% 
    mutate(medblood=median(blood)) %>% 
    spread(tag,id) %>% select(-blood) %>% 
    select(-medblood,medblood)
# A tibble: 6 x 5
  `age_20-29` `age_30-39` edu_Primary edu_Secondary medblood
        <int>       <int>       <int>         <int>    <dbl>
1          NA           1           1            NA     8.70
2           1          NA          NA             1     8.70
3           2          NA          NA             2    10.0 
4          NA           1           1            NA     8.70
5           2          NA          NA             2    10.0 
6          NA           2           2            NA    10.0 
That last select(-medblood,medblood) moves the median blood column to the far right. You might possibly be wanting to do this though:
> group_by(df,id,age) %>% gather(variable,value,age,edu) %>% 
    unite(tag,variable,value) %>% 
    mutate(medblood=median(blood)) %>% 
    count(medblood,id,tag) %>% spread(tag,n)
# A tibble: 2 x 6
# Groups:   id [2]
     id medblood `age_20-29` `age_30-39` edu_Primary edu_Secondary
  <int>    <dbl>       <int>       <int>       <int>         <int>
1     1     8.70           1           2           2             1
2     2    10.0            2           1           1             2
Here is the dput of the data df used for this example:
> dput(df)
structure(list(id = c(1L, 1L, 1L, 2L, 2L, 2L), age = structure(c(2L, 
1L, 2L, 2L, 1L, 1L), .Label = c("20-29", "30-39"), class = "factor"), 
edu = structure(c(1L, 2L, 1L, 1L, 2L, 2L), .Label = c("Primary", 
"Secondary"), class = "factor"), blood = c(5.5, 8.7, 10, 
11, 10, 9)), .Names = c("id", "age", "edu", "blood"), class = "data.frame", row.names = c(NA, 
-6L))