Statistic analysis x = categorical, y = boolean in R I have a data frame:
age <- c("10-20", "10-20", "21-30", "21-30", "31-40", "31-40")
happy <- c(TRUE, TRUE, TRUE, FALSE, FALSE, TRUE)

df <- data.frame(age, happy)

I want to do a statistical analysis testing the null hypothesis that there is no difference between age classes in terms of happiness.
Would I use a chi squared test for this? or binary logistic regression? I thought maybe binary logistic regression would be unsuitable because x is categorical rather than continuous
This is what I have tried so far, it gives an output, but I'm not sure it's meaningful:
model <- glm(happy ~ age, family = binomial(link = 'logit'), data = df)

 A: @Michael M has the right answer.  A chi-squared test is asymptotically the same as what you would get from a logistic regression model here, although the p-values will typically vary slightly if you don't have infinite data.  More technically, the chi-squared test is a score test, whereas the typical tests used with logistic regression models are Wald and likelihood ratio tests (to understand this more fully, it may help to read my answer here: Why do my p-values differ between logistic regression output, chi-squared test, and the confidence interval for the OR?).  
However, if you fit a logistic regression model using reference level coding (cf., here), you will prevent the model from recognizing, and taking advantage of, the ordinal nature of age.  In your case, the minimum and maximum possible values are bounded, which makes your situation a little simpler.  We might guess that the expected value of age within each bin is the mean of the endpoints.  So you could just substitute a continuous value for each person in place of their listed age category.  That is:
\begin{align}
\{10-20\} \rightarrow 15.5 \\
\{21-30\} \rightarrow 25.5 \\
\{31-40\} \rightarrow 35.5
\end{align}
Then you can use the new continuous age variable in your logistic regression model.  People find this surprising, but the potential for error is just $\pm5$, and the range of your data is $30$, so the induced measurement error shouldn't play that big of a role.  Note that when people give their actual age (say, $29$), that is also typically a kind of rounded value instead of their exact age (perhaps, $29.2789274$).  There are fancier ways to try to deal with this, but I wouldn't typically bother with them.  
Here is an example with your sample data, coded in R:  
age = c(15.5, 15.5, 25.5, 25.5, 35.5, 35.5)
summary(glm(happy~age, family=binomial))
# 
# Call:
# glm(formula = happy ~ age, family = binomial)
# 
# Deviance Residuals: 
#       1        2        3        4        5        6  
#  0.4659   0.4659   0.8350  -1.5640  -1.0061   1.3590  
# 
# Coefficients:
#             Estimate Std. Error z value Pr(>|z|)
# (Intercept)   4.1683     3.8201   1.091    0.275
# age          -0.1292     0.1310  -0.986    0.324
# 
# (Dispersion parameter for binomial family taken to be 1)
# 
#     Null deviance: 7.6382  on 5  degrees of freedom
# Residual deviance: 6.4364  on 4  degrees of freedom
# AIC: 10.436
# 
# Number of Fisher Scoring iterations: 4

A: Try encoding the age levels into dummy binary variables (remember to avoid the dummy variable trap) and use these variables as inputs to a logistic regression. Even if there is no linear dependency between age (as continuous) and happyness, you will still be able to capture the dependence.
Another option (a straightforward one) is to use analysis of variance where you make Happy the factor and use Age as pseudo-continuous variable. The analysis will show if average Age varies significantly across being happy.
