views:

109

answers:

3

Hi,

I want to be able to give codes to potential users in the form of email links (e.g. mysite.com/signup?beta=rapunzel)

When someone clicks on the link, it populates a hidden_field with the value (will just using :params[:beta] work?)

Then before it creates the user it validates by checking against another table where I have different beta code.

Then goes ahead and stores which code or maybe just the beta.id.

Suggestions? A plugin already exists?

Thanks.

A: 

When your user hits mysite.com/signup, the action associated with that route will have the value "rapunzel" stored in params[:beta]. You can pass that onto your view by assigning it into an instance variable (@beta), pass it back to your user controller through your hidden field as planned, and compare it there to your table before saving the user object.

Or you could only allow your user to get to the signup page at all if they're passing in a valid beta code, in which case you won't need any special form fields:

def signup
  unless BetaCode.find_by_code(params[:beta])
    flash[:notice] = "You can't sign up without a beta code!"
    redirect_to root_path 
  end
end
Raphomet
ah, so the model is BetaCode which has several rows with different values for beta (e.g. BetaCode.id and BetaCode.beta) and the "unless" clause would check all values and if it didn't find it, it would be an invalid signup page?
Angela
That's right. Unless is the same as "if !clause". It's one of Ruby's pretty but confusing idioms and lots of people don't use it for that reason - it's a personal style thing. :)And, yes, that is how I envisioned BetaCode from your description in the original question: a table of entries with valid beta codes, with the rows "id" and "code". How you actually do this is up to you of course, and Daemin's has_one suggestion is a pretty good one.
Raphomet
A: 

What parameters you get out of your URL will depend on how your routes are set up. With your current route you would get:

params[:beta] = "rapunzel"

If you specify your route as:

map.connect '/signup/:beta', :controller => 'signup', :action => 'beta'

you could send them a link like: mysite.com/signup/rapunzel instead and you would get the beta parameter the same as before.

To get the beta field onto the form just include it as a hidden field on the form page template.

In the controller put something like:

@beta_id = params[:beta]

Then in the view template put:

hidden_field_tag 'beta', @beta_id

Then when they signup and create a proper id you'll probably want to hook in an association from their row in the user's table to the row containing the beta id in the "beta" table. This could be a has_one association on the beta table if you only wanted to allow a single user to register with each beta id, or a has_many if multiple people could sign up with it.

Daemin
Hi, okay, cool...I guess the has_many association is what I'm looking for...so supposed I create a table beta with beta.id as one column and beta.beta as the other (?) do I create a validation to do the check or how do I check that it is valid?
Angela
Yes, you could use validations to check if the beta id is valid. It could be added as a validation that gets run when a new user gets registered. If you wanted to make it more secure (so that you couldn't create a beta account without it) I'd add it to the controller as well as a validation to the model.
Daemin
+1  A: 

I would have done this with a validation.

class User < ActiveRecord::Base
  validate_on_create {|r|
    beta_code = BetaCode.find_by_code(r.beta_code)

    beta_code && beta_code.destroy ||
      r.errors.add(beta_code, "is invalid")
  }

  attr_accessor :beta_code
end

In your form:

<% form_for(@user) do |f| %>
  # fields...
  <%= f.text_field :beta_code %>
<% end %>

This assumes that you have a BetaCode model whose table contains a list of beta codes.

August Lilleaas
You _definitely_ only want to do this validation on creation, not every time the User object is saved. Otherwise, this is a good approach.
James A. Rosen
Good point, updated the snippet.
August Lilleaas