ActiveRecord .new not working, any ideas why? - ruby-on-rails

I know it is broad question but I am really confused.
I have table users and columns :username, :pwd_hash, :first_name, :last_name etc.
When I try to create new instance with
user = User.new(:username => 'Foo', first_name => 'Bar')
puts user.inspect
and I inspect user I get that all properties set to nil. If I do get existing user all is set properly with User.find(1) so DB is setup correctly. Also there are columns with same name in DB. Using ruby 1.9.3 on Windows.
Again I know it is stupid question but I am despreate I am wondering if anybody had similiar problem. Thank you.

This can happen if your User model uses attr_protected or attr_accessible to prevent username or first_name from being mass-assigned.

Related

Redacting a SSN on form display under Rails 4?

I have a Rails 4 application and I am using the attr_encrypted gem to store SSN in an encrypted form in the DB.
What I am trying to do is only display the last 4 digits when editing / showing the form. So essentially once the SSN has been saved, users can't see the full SSN in the form. So I've tried doing the following,
class PaymentData < ActiveRecord::Base
attr_encrypted :ssn, key: 'secret'
alias_method :org_ssn, :ssn
def ssn
org_ssn.reverse # just a way of testing if this works
end
end
What I am seeing that the on the show form, which uses <%= #payment_data.ssn %>, it works fine. But on my edit form which is using <%= f.input :ssn %>, the edit field is prepopulated with the full SSN.
Note: I am using the simple_form gem for my forms, but if I use the basic, <%= f.text_field :ssn %> syntax, I see the same full SSN.
What am I doing wrong here?
This is what I ended up doing,
def obfuscated_ssn
return ssn unless ssn && ssn.size > 3
ssn.last(4).rjust(ssn.length, '*')
end
def obfuscated_ssn=(ssn)
self.ssn = ssn unless ssn.include?('*')
end
This is a bit hacky, but it displays the SSN with a redacted string, but then doesn't save a string with the redacted bits, *, to keep bad data from getting the database.
I suggest something different.
Keep your obfuscated_ssn method from your answer, it makes sense to have it in the model. However overriding the setter like this... well I'd go a different way.
What I don't really like, is that you are doing validations in the setter. I checked the gem page but couldn't find anything related to validation, but normally your model would include validation rules like
validates_length_of :ssn, :minimum => 5, :maximum => 20, :allow_blank => true
I don't know if the ssn gem is clever enough to run the validations only on non-encrypted data though...
But anyway here's how I would tweak your form/controller :
Your form
you would need to figure out how to display one field and submit to a completely different one
I suggest changing the default value shown by the field (Ruby doc for text_field :)
f.text_field(:ssn, :value => f.object.obfuscated_ssn)
Now I'm not sure about the behavior you want. Is the user supposed to always write the ssn field? Or do you want to leave it unchanged in case the user doesn't enter anything ? If so I'd put some checks on your controller
Controller
def model_params
if params[:your_model][:ssn] == #model.obfuscated_ssn
params[:your_model].delete(:ssn) # Make sure your model doesn't get updated with obfuscated ssn
end
params.require(:your_model).permit(:ssn, etc.)
end

Rails simple validations not working

class User < ActiveRecord::Base
attr_accessible :email, :name
validates :name,:presence=>true,
:length=>{:maximum=>15}
validates :email,:presence=>true,
:length=>{:maximum=>15}
end
I am new to rails and the simplest of the validators are not working. I think I may be making a very silly mistake . I have a User model with 2 attributes only and when I create a new user in ruby console with wrong validations like no name or a longer name than 15 characters it gets added happily Please suggest.I am using rails version:3.2.13 and ruby version:1.9.3
If you are on rails console, be sure to type reload! after making changes to models. In this way, all changes will be reloaded in the console instance.
Moreover, are you sure you are saving these models? You should try something like this:
user = User.new(email: "john.doe#gmail.com")
user.save
If the result of the last line is false, you can view the validation errors with
p user.errors

Rails - Skip rails validation for subclass

I have a User class, and a Contact where Contact is a subclass of User. Both classes are stored in a users table.
My Contacts may or may not have an email address, while an email address is required for my Users (I have validates_presence_of :email in my User model definition).
My reasoning is that Contacts are entered by users and may later become Users when they claim their profile.
First of all, is it ok to define my
users and contacts the way I did it?
Second, how do I skip the
validate_presence_of email
validation in my contacts model?
(I'm on rails 2.3.8)
Thanks!
UPDATE:
It seems Single Table Inheritance is
designed to do exactly what I needed
the right way to skip validation for
the presence of email for my Contact
table is as follow:
validates_presence_of :email, :unless => Proc.new {|user| user.type == "Contact"}
It sounds like you should abstract out User and Contacts into two tables instead of trying to consolidate them into one. Although contacts can become users, that doesn't mean that they will (I think?).
This would also solve your validate_presence_of :email question, as the contact table/model wouldn't even have the field. It would also alleviate potential performance concerns later on, I believe. You wouldn't want to have a ton of contacts to sort through to find a registered user.
If you're dead-set on doing it in one table though, I believe you can do something like the following:
validates_presence_of :email, :unless => Proc.new {|user| user.type == "Contact"}
This is assuming that you have a user_type column, but you could replace that depending on how you're determining whether a User is a Contact.
Update:
This is how you'd correctly validate the models: Remove the validates_presence_of from the model and place it inside of this block:
with_options :unless => :user_type == "contact" do |user|
user.validates_presence_of :email
end

Rails Seed confusion

I'm having trouble seeding my database using seed.rb, specifically where table relationships are concerned.
Here's a sample of the code:
# seed.rb
user = User.find_or_create_by_login(
:login => "myname",
:email => "myname#gmail.com",
:user_type => "Admin",
:password => "admin",
:password_confirmation => "admin")
project = Project.find_or_create_by_user_id(
:user_id => user.id,
:name => "Test Project")
When project is created (along with other unrelated parameters I've left out from above), user_id is empty. How can I get this to work?
This is the strangest behavior I've seen in something so simple. In my seed file, I have about eight tables being created and some are nested 3-4 levels deep (i.e. user has_many projects; projects has_many tasks, etc.).
When I call user user as above and reference user.id multiple times after that, it only works once! I tried adding [user.reload] before each new record is created but to no avail. I don't imagine this will make sense to anyone, but are there any possibilities here? Thanks all.
I figured out what the problem was. The fields that weren't populating were not listed explicitly in attr_accessible in their respective models. The fields listed were being saved correctly.
Thank you very much for your help everyone.
The code is fine and is the correct syntax for find_or_create. As others have said the most likely problem is that the user is invalid. Trying to call user.reload would make it blow up if the user is invalid and so will kind of make the problem more apparent, but the error you'll get from it will be useless (it'll moan about not being able to find a user without an id).
Unfortunately find_or_create doesn't work as a bang method to raise exceptions if it's invalid, so the best thing to do is probably raising an error and outputting the error after attempting to create the user:
user = User.find_or_create_by_login(:login => "myname")
raise "User is invalid: #{user.errors.full_messages}" unless user.valid?
User created with success? if so..try user.reload if not. that is probably the error
Are you sure your user is saved? I think the right syntax for find_or_create_by_XX is Blog.find_or_create_by_title("Some Blog"). If you need to pass more data you need to use find_or_initialize first and set other data after that separately.
Loosely related thread: Rails find_or_create by more than one attribute?
--edit
Passing data as hash to find_or_create_by_XX seems to work too. Docs are under "Dynamic attribute-based finders" here http://apidock.com/rails/v3.0.0/ActiveRecord/Base
try this
use User.find_or_create instead of User.find_or_create_by_login.
It seems like your user object is not saved.
Or before you assign user.id do user.reload
user = User.find_or_create(
:login => "myname",
:email => "myname#gmail.com",
:user_type => "Admin",
:password => "admin",
:password_confirmation => "admin")
[user.reload]
project = Project.find_or_create_by_user_id( :user_id => user.id,
:name => "Test Project")

Ruby on Rails Validation Question Inside Controller

Let's say I have a form_tag in a view gathering a view user input . With this input that I get through the params hash, I want to verify some of htis information such as email phone name.
Can I just verify in the controller or is this a bad thing? I don't plan to save the thing I get to a db or anything, it's just getting put into an email and sent off, but I want to verify these things before it's sent.
Thank you.
EDIT:
Found this http://www.viddler.com/explore/rails3/videos/6/
class Test
include ActiveRecord::Validations
validates_presence_of :name, :email
attr_accessor :name, :email
end
You can use the model for whatever you need that is related to the object and don't need to save it. Keeping stuff like this in the model is desirable in order to keep controller tidy. Say you have a user model:
#controller
#user.new params[:user]
#user.check_valid
#user.save # is optional
#user.rb
def check_valid
!email.blank? and !phone.blank?
end

Resources