Two models one form. A lot of headache

Hi everyone,

I building a sign up form using two models. One to keep the regular
user information and the second to keep login and password. I got
everything working out except for some little details that I can’t
figure out how to handle.

My models are User and Login. Login has_one User and User belongs_to
Login. Using the User controller I built a action called new which
display the signup form and save the information in the two different
databases. The action is working except for the fact that is not
saving the Login id in the column login_id at User as was supposed to
do and for some weird reason is not saving the boolean fields in any
of the databases.

Below I’m pasting my codes so you can give me some light.

#database structure

class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.column :full_name, :string
t.column :street_address, :text
t.column :city, :string
t.column :state, :string
t.column :country, :string
t.column :zip_code, :integer
t.column :phone, :integer
t.column :email, :string
t.column :birth_date, :date
t.column :policy_agreement, :boolean
t.column :created_at, :timestamp
t.column :updated_at, :timestamp
end
end

def self.down
drop_table :users
end
end

class CreateLogins < ActiveRecord::Migration
def self.up
create_table :logins do |t|
t.column :login, :string
t.column :password, :string
t.column :ip_address, :string
t.column :status, :boolean
end
add_column :users, :login_id, :integer
end

def self.down
drop_table :logins
remove_column :users, :login_id
end
end

#models code

class Login < ActiveRecord::Base
has_one :users
validates_uniqueness_of :login
validates_presence_of :login
validates_confirmation_of :password, :message => “should match
confirmation.”
end

class User < ActiveRecord::Base
belongs_to :logins

validates_presence_of :full_name
validates_presence_of :street_address
validates_presence_of :city
validates_presence_of :state
validates_presence_of :country
validates_presence_of :zip_code
validates_numericality_of :zip_code, :only_integer => true, :message
=> “must contain only numbers.”
validates_presence_of :phone
validates_numericality_of :phone, :only_integer => true, :message =>
“must contain only numbers.”
validates_presence_of :email
validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+.)+[a-
z]{2,})$/i
validates_uniqueness_of :email
validates_acceptance_of :policy_agreement, :message => “must be
accepted. You have to read and agree with the Aykall Policies before
signing in.”
validates_multiparameter_assignments :message => " is not a valid
date."
validates_each :birth_date do |record, attr, value|
record.errors.add attr, “is not a valid date. You must be at
least 18 years old to sign in.” if value > Date.new((Date.today.year -
18),(Date.today.month),(Date.today.day))
end
end

controller code

class UserController < ApplicationController
layout ‘standard’

def new
case request.method
when :post
@user = User.new(params[:user])
@login = Login.new(params[:login])
@user.valid?
@login.valid?
if @user.save
flash[:notice] = ‘Your use account was successfully created.’
redirect_to :action => ‘search’
end
end
end

end

view code

Add a new user

<%= error_messages_for ‘user’, ‘login’ -%>

<% form_for :user, @user, :url => { :action => “new” } do |user_form|
%>

Full Name: <%= user_form.text_field :full_name %>

Street Address: <%= user_form.text_field :street_address %>

Country: <%= user_form.country_select :country %>

State: <%= user_form.text_field :state %>

City: <%= user_form.text_field :city %>

Zip Code: <%= user_form.text_field :zip_code %>

Phone: <%= user_form.text_field :phone %>

email: <%= user_form.text_field :email %>

Policy Agreement: <%= user_form.check_box :policy_agreement %>

Birthdate: <%= user_form.date_select :birth_date, :use_short_month
=> true, :start_year => 1900, :order => [:month, :day, :year] %>

<% fields_for :login, @login do |login_form| %>
  Login: <%= login_form.text_field :login %><br>
  Password: <%= login_form.password_field :password %><br>
  Password Confirmation: <%=

login_form.password_field :password_confirmation %>

<%= login_form.hidden_field :ip_address, :value =>
request.env[‘REMOTE_IP’] %>
<%= login_form.hidden_field :status, :value => ‘0’ %>
<% end %>



<%= submit_tag “Join Now” %>

<% end %>

Let me ask something else. Do you guys think that is safe to store
passwords in a string field using MySQL? Is there any other way that
is more secure?

Thanks
Thiago G.

Thiago G. wrote:

Hi everyone,

I building a sign up form using two models. One to keep the regular
user information and the second to keep login and password. I got
everything working out except for some little details that I can’t
figure out how to handle.

Thanks
Thiago G.

I think this would get more responses if you had broken your various
questions up into different posts.

  1. The action is working except for the fact that is not saving the
    Login id in the column login_id at User as was supposed to do.

This sounds like maybe a confusion rather than something not working.
Me thinks that with the relationship you are using, Login objects know
about their User, but I don’t understand why you are hoping to get
“my_user.login_id”.

  1. for some weird reason is not saving the boolean fields in any of the
    databases.
    Sorry, no clue on this one.

  2. Let me ask something else. Do you guys think that is safe to store
    passwords in a string field using MySQL? Is there any other way that
    is more secure?
    No, not safe. You are re-inventing a complex wheel here. Have a look
    at the ActsAsAuthenticated plugin and save yourself a lot of time. It
    will do all of the login stuff for you. Very easy to use.

cheers,
jp

First of all, thanks for your help.

I’m very new to Ruby on Rails. I’m reading the book “Ruby on Rails
made Easy” and as I do it I’m trying to develop my application.
So, what you are saying is that with the relation has_one and
belongs_to between my two models there is no need for such a column as
login_id in my User database? Rails will automatically know that the
information placed in row number 132 on my users table belongs to the
row 136 in my logins table? I’m just asking again because it just
seems to clever to be true. kkk

Thanks,
Thiago G.

On Nov 4, 3:59 pm, Jeff P. [email protected]

On 4 Nov 2007, at 16:09, Thiago G. wrote:

  @user = User.new(params[:user])
  @login = Login.new(params[:login])
  @user.valid?
  @login.valid?

There’s no way it’s going to magically know that the login created is
being created for the user in question.
You probably want @user.build_login(params[:login)

Fred

You need the joining columns in the database. Active Record won’t
create them for you.

In order to express the relationships you need to use build (as last
post here), otherwise you can explicitly set the ID’s as you want. As
it is, your relationship is bi directional so you’re going to have to
create one, create the other using build from the first one (which
will set the foreign key context for you). Finally you are going to
need to get the ID of the new record created through build and update
the parent record so you have the relationship at both ends. This is
because you can’t know the child’s key until you’ve created it. Once
this is done it will work fine and login.user and user.login will be
available to you in your code.

login.create(params[:login])
user = login.build.user(params[:user])
login.update_attribute(:user_id => user.id)

The only question for me is why have a bi-directional relationship? I
have done this when I’ve used the acts as authenticated plugin so as
not to pollute the plain user table, but if you are hand-crafting this
you can do whatever you want. You can create an accessor method in the
login class

def user

Hope this helps

… I pressed a control key and it posted on me …

See added in code

On Nov 5, 8:38 am, ghoti [email protected] wrote:

because you can’t know the child’s key until you’ve created it. Once
you can do whatever you want. You can create an accessor method in the
login class

def user
@user ||= User.find_by_login_id self.id
end

This will give the effect you want without the bi -directional stuff
in Active Record