Cannot Define Attribute in Create method Rails - ruby-on-rails

In rails 4.2.4, I can successfully execute this line of code.
Model.Create!(name: "Bob")
In Rails 4.2.5, this does nothing and leaves me with a null field in the database. To get past this, I must do something like this...
s = Model.Create!()
s.name = "Bob"
s.save!
Does anyone know why the first method doesn't work? Has rails been updated to something different? I haven't been able to find a solution for this. Thanks in advance.

Difference Between Model.create() and Model.new()
Model.create() It will create and save empty columns DB, if its not "validated".
Model.new() It will create empty table but not saves it in DB. Until will not be saved.
Example:
u = User.new
u.first_name = 'Joe'
u.last_name = 'Doe'
u.save #this saves DB.
Here is good Examples

Related

Ruby on Rails: Update Attribute

Google is seriously failing me right now. All I need to do is update one attribute, setting a user to admin, from the Heroku rails console.
I can't find a single simple answer. What I've been trying is:
Record.update_attribute(:roles_mask, "1")
Where record is the correct record.
'undefined method 'update attribute''
I can't just type Record.roles_mask = 1?
EDIT.
I used Record, and I shouldn't have done that in the example. What I've done is exactly this:
ian = User.where(:id => '5')
ian.update_attribute(:roles_mask, '1')
Error: undefined method 'update_attributes'
The problem is that using the .where function creates a relation, rather than finding the record itself. Do this:
ian = User.find(5)
ian.update_attribute(:roles_mask, '1')
Or if you want to use .where then you could do this:
ian = User.where(:id => 5)
ian.first.update_attribute(:roles_mask, '1')
EDIT
See this answer for details about why this is happening.
To use update_attribute (or update_attributes), you need to call that from an instance and not the class.
rails c> rec = Record.find(1)
rails c> rec.update_attribute(:att, 'value')
rails c> rec.update_attributes(att: 'value', att2: 'value2')
I would think that should take care of your issue.
Where clause return a array and you are trying to make update query on array, that's why you got error.
you should try to find out first record
ian = User.where(:id => 1).first
or
ian = User.find(1)
or
ian = User.find_by_id(1)
now your update query will work.
ian.update_attribute(:roles_mask, '1')

Rails console - TypeError: can't cast Hash to string

A little background first, I was able to get the - Angular/Rails project working on local
I went to change the user/password in sqlite3 and here are the steps that I took
rails c
a = User.find(1)
a.name = "myName"
a.password_digest = "mySurName"
a.save
Great, it worked! NOT
Well, kind of, but the Angular app is looking for a password that looks something like this - $2a$10$TrTjNCWr5KlwW2h9aJr45u8MwLDo2ErEFQp1/ixc.8KW...
After doing some digging, I found a stackoverflow answer
Followed by me trying to do the following:
a = User.find(1)
filters = Rails.application.config.filter_parameters
f = ActionDispatch::Http::ParameterFilter.new filters
b = f.filter :password_digest => 'mySurName'
a.password_digest = b
Which results in an error that is in the subject line of this post - TypeError: can't cast Hash to string, followed by (0.1ms) rollback transaction and tons of lines of references to .rb files
So, my ultimate question is, how do I update a record that has a filter on a password field, while using rails console?
Thanks in advance
You should read up on password hashing and storage, your password should never be stored as plaintext. Just a hunch, try this instead:
a = User.find(1)
a.name = "whatever"
a.password = "something"
a.save
In devise (and probably others) a password setter is defined for the User model which automatically stores the hash of the password in the password_digest column.
OK, while reading another post to something that was somewhat unrelated - here's the answer:
a = User.new(:name => "Luke", :password => "Skywalker", :password_confirmation => "Skywalker")
a.save
Which creates something like this:
password_digest: "$2a$10$OPlc1rCZscqPkFYSp10NQeTmDRNs1iuv6D0VLAKk8sXu..."

Converting Rails model to SQL insert Query?

Is there a way to convert a Rails model into an insert query?
For instance, if I have a model like:
m = Model.new
m.url = "url"
m.header = "header"
How can I get the corresponding SQL query ActiveRecord would generate if I did m.save?
I want to get: "INSERT INTO models(url, header) VALUES('url', 'header')" if possible.
Note: I don't want to actually save the model and get the query back (from log file, etc). I want to get the query IF I chose to save it.
On Rails 4.1, I found the below code snippet working:
record = Post.new(:title => 'Yay', :body => 'This is some insert SQL')
record.class.arel_table.create_insert
.tap { |im| im.insert(record.send(
:arel_attributes_with_values_for_create,
record.attribute_names)) }
.to_sql
Thanks to https://coderwall.com/p/obrxhq/how-to-generate-activerecord-insert-sql
Tested in Rails 3.2.13: I think I got it right this time, it definitely does not persist to the db this time. It also won't fire validations or callbacks so anything they change won't be in the results unless you've called them some other way.
Save this in lib as insert_sqlable.rb and you can then
#in your models or you can send it to ActiveRecord::Base
include InsertSqlable
Then it is model.insert_sql to see it.
#lib/insert_sqlable
module InsertSqlable
def insert_sql
values = arel_attributes_values
primary_key_value = nil
if self.class.primary_key && Hash === values
primary_key_value = values[values.keys.find { |k|
k.name == self.class.primary_key
}]
if !primary_key_value && connection.prefetch_primary_key?(self.class.table_name)
primary_key_value = connection.next_sequence_value(self.class.sequence_name)
values[self.class.arel_table[self.class.primary_key]] = primary_key_value
end
end
im = self.class.arel_table.create_insert
im.into self.class.arel_table
conn = self.class.connection
substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
binds = substitutes.map do |arel_attr, value|
[self.class.columns_hash[arel_attr.name], value]
end
substitutes.each_with_index do |tuple, i|
tuple[1] = conn.substitute_at(binds[i][0], i)
end
if values.empty? # empty insert
im.values = Arel.sql(self.class.connectionconnection.empty_insert_statement_value)
else
im.insert substitutes
end
conn.to_sql(im,binds)
end
end
It turns out the code is in ActiveRecord::Relation and not ActiveRecord::Persistence. The only significant change is the last line which generates the sql instead of performing it.
If you dont want to save the model you call m.destroy when you are done with the object.
You can log the sql query by debugging it like this
Rails.logger.debug "INSERT INTO models(url, header) VALUES(#{m.url}, #{m.header}).inspect
After search a lot over the Internet and forums, I think I found a better solution for your problem: just requires two line of code.
I found a good gem that do exactly what you want, but this gem only works for Rails 3.2 and older. I talked with author and he doesn't want support this gem anymore. So I discovered by myself how to support Rails 4.0 and now I'm maintaining this gem.
Download the "models-to-sql-rails" gem here, supporting Rails 4.0 and older.
With this gem, you can easily do the following. (the examples inside values are just a joke, you will get the correct values when using it in your object).
For objects:
object.to_sql_insert
# INSERT INTO modelName (field1, field2) VALUES ('Wow, amaze gem', 'much doge')
For array of objets:
array_of_objects.to_sql_insert
# INSERT INTO modelName (field1, field2) VALUES ('Awesome doge', "im fucking cop")
# INSERT INTO modelName (field1, field2) VALUES ('much profit', 'much doge')
# (...)
Just see the Github of this project and you'll find how to install and use this wonderful gem.

Ruby - how to create dynamic model attributes?

I have an array with model attributes (these model attributes are columns in DB table). I am trying to iterate through this array and automatically create a record which I would like to save to DB table, something like this:
columns.each_with_index do |c, i|
user.c = data[i]
puts user.c
end
user is model.
But if I try the snippet above, I get
undefined method `c=' for #<User:0x007f8164d1bb80>
I've tried also
columns.each_with_index do |c, i|
user."#{c}" = data[i]
puts user."#{c}"
end
But this doesn't work as well.
Data in columns array are taken from form that sends user, so I want to save only data that he send me, but I still cannot figure it out...
I would like to ask you for help... thank you in advance!
user.send("#{c}=".to_sym, data[i])
Also, you can access the attributes as a hash.
user.attributes[c] = data[i]
The best thing would probably be to build a hash and to use update_attributes:
mydata = {}
columns.each_with_index{|c, i| mydata[c] = data[i]}
user.update_attributes(mydata)
this way you retain the protections provided by attr_accessible.
If this is actually in a controller, you can just make use of some basic rails conventions and build the User record like this:
#user = User.new(params[:user])
if #user.save
# do something
else
# render the form again
end
Although you can set the values using send, I agree with #DaveS that you probably want to protect yourself via attr_accessibles. If your planning to use Rails 4, here's a good overview.

deleting attributes from ActiveRecord model

I'm migrating data between two activerecord connections, I've got my models all setup correctly so I can read from say Legacy::Tablename and Tablename and insert it into the new table.
The problem I have is my new model doesn't have all of the attributes that are in the legacy model so I get an 'unknown attribute' when I try to create a record in the new model via;
legacy_users = Legacy::User.all
legacy_users.each do |legacy_user|
User.create legacy_user.attributes
end
however if I try to remove the offending attribute it still doesn't work eg.
legacy_user.attributes.delete 'some_attribute'
Can anyone offer any pointers?
How about attributes.except(:some_attribute)?
This should work in that case:
legacy_users = Legacy::User.all
legacy_users.each do |legacy_user|
u = User.new
u.attributes.each do |k, v|
old_val = legacy_user.send(k) # Get the attr from old user
u.send("#{k}=", old_val) # Set it to the new user
end
end
You won't need to go through the mess of removing each unused attribute too
I'm working on a migration as well, and in my case I was passing a block to first_or_create to clone objects. I couldn't get delete() or except() to work, but for some reason this works:
scrubbed_obj = my_obj.attributes.reject { |k,v| k == 'the_attribute_you_dont_want' }
new_object.attributes = scrubbed_obj
and then the block saves fine. Just throwing dropping this answer here in case anyone else is experiencing similar issues.

Resources