Ruby on Rails: Updating data problems - ruby-on-rails

Okay so I'm just trying to write some simple code that updates a record given an ID. This is what it looks like.
def updaterecord
bathroom = Bathroom.find(params[:key])
bathroom.name= params[:name],
#bathroom.bathroomtype = params[:bathroomtype],
bathroom.street = params[:street]
#bathroom.city = params[:city],
#bathroom.state = params[:state],
#bathroom.country = params[:country],
#bathroom.postal = params[:postal],
#bathroom.access = params[:access],
#bathroom.directions = params[:directions],
#bathroom.comment = params[:commment],
#bathroom.avail = params[:avail]
bathroom.save
end
The problem is that although I am trying to update each individual attribute they are all getting concatenated to the name field. For example, this code above sets the name field to the name plus the address. I don't know why?
This is what the console looks like if I try to query after doing the update.
Bathroom Load (0.2ms) SELECT "bathrooms".* FROM "bathrooms" WHERE "bathrooms"."ID" = ? LIMIT 1 [["ID", 4017]]
=> #<Bathroom ID: 4017, name: "--- \n- ttyt\n- 113 some\n", bathroomtype: "0", street: "113 some", city: "Portland", state: "OR", country: "United States", postal: "97217", lat: #<BigDecimal:1109f2890,'0.4558056E2',12(12)>, lon: #<BigDecimal:1109f27c8,'-0.122677857E3',12(16)>, access: "0", directions: "", comment: nil, created: "2012-06-08 17:19:03.420329", modifed: "", avail: "1", slug: "", source: "Squat">
And this is what the post values look like:
post values = key=4017&name=www&bathroomtype=0&street=7540 N Interstate Ave&city=Portland&state=OR&country=United States&postal=97217&access=0&directions=&comment=<null>&avail=1
Why can't I get each field to update individually? Sorry I'm confused as to what is going on?

I think you might an unnecessary comma there at the end of the line.
It should just read:
def updaterecord
bathroom = Bathroom.find(params[:key])
bathroom.name= params[:name]
bathroom.street = params[:street]
bathroom.save
end

it doesn't look like you have correctly urlencoded your post values
a simple
puts params.inspect
or
pp params
should log out the params object. You can also use
render :text => params.inspect
to print it out to your result html

Related

Rails translate enum in an array

I am currently working on statistics, so I get an array containing all my data. The problem is that this data contains enums and that I would like to translate them without overwriting the rest.
Here is a given example that contains my array (it contains several hundred) :
#<Infosheet id: 90, date: "2018-04-22 00:00:00", number: 7, way: "home", gender: "man", age: "age1", district: "", intercommunal: "", appointment: true, othertype: "", otherorientation: "", user_id: 3, created_at: "2018-04-22 17:51:16", updated_at: "2018-04-22 17:51:16", typerequest_id: 168, orientation_id: 188, info_number: nil, city_id: 105>
I would like to translate the enums of "way" or "gender" or "age", while retaining the rest of the data, because currently, if I make a translation in the console, it crushes everything else.
Do you know how to make that ?
Thanks !
You can just loop over all the enum attributes and get their values. Later you can merge and pass a new hash containing converted values
ENUM_COLUMNS = %i[way gender age] # Equivalent to [:way, :gender, :age]
def convert_enums
overrided_attributes = {}
ENUM_COLUMNS.each { |column| overrided_attributes[column.to_s] = self[column] }
attributes.merge(overrided_attributes)
end
NOTE:
While infosheet.gender returns you male or female
infosheet[:gender] will return you the respective integer value 0 or 1
You can test this if you use translate enum gem :
a = Infosheet.group(:gender).count
{“male”=>30, “female”=>6532}
Create a hash
r = Hash.new
And populate this with :
a.each {|s| puts r[Infosheet.translated_gender(s[0])]=s[1] }
r
result :
{“homme”=>30, “femme”=>6532}

creating multiple records with a single JSON post

The following parameters are being posted
Parameters: {
"orig_id"=>47,
"terms_accepted"=>true,
"email"=>"sod#gos.co",
"name"=>"firstname",
"surname"=>"surname",
"kids"=>[
{"school"=>"Faraway", "rate"=> "89"},
{"school"=>"Transfer", "rate"=> "23"},
{"school"=>"Bike", "rate"=>"4"}]
}
However, the rails controller action, defined as follows only creates the parent record, but not the related ones:
parent = params[:parent]
#parent = Parent.new(orig_id: parent['orig_id'], terms_accepted: parent['terms_accepted'], email: parent['email'], name: parent['name'], surname: parent['surname'])
#parent.save
kids = params[:kids]
kids each do |kid|
#kid = Kid.new(school: kid['school'], rate: kid['rate'], parent_id: #parent.id)
#kid.save
end
where is the syntax wrong?
kids each do |kid| actually should be kids.each do |kid|.

ActiveRecord on local console not working, but works with Heroku

I'm rather baffled right now.
I have a database full of airport data. I'm trying to call certain attributes from different records in my console, but it isn't working. Oddly enough it works fine in my heroku console. For example:
If I put: x = Airport.where(code: "JFK"). When I type "x" in my console I get the entire record for JFK. But, when I type x.runway_length I get a method error.
The odd thing is when I do the same process in my Heroku console, I'll get the runway length (or any other attribute I attach to "x").
What's going on? Am I missing something.
Thanks!
x = Airport.where(code: "LAX")
Airport Load (2.9ms) SELECT "airports".* FROM "airports" WHERE "airports"."code" = 'LAX'
=> #<ActiveRecord::Relation [#<Airport id: 3533, code: "LAX", lat: 33.9456, lon: -118.391, name: "Los Angeles International Airport", city: "Los Angeles", state: "California", country: "United States", woeid: 12520706, tz: "America/Los_Angeles", phone: "", email: "", url: "", runway_length: 12091, elev: 126, icao: "KLAX", direct_flights: 200, carriers: 99, created_at: "2015-08-06 19:10:03", updated_at: "2015-08-17 03:05:53", current_high_temp: 84, current_low_temp: 70>]>
Now, when I try: x.current_high_temp
NoMethodError: undefined method `current_high_temp' for #<ActiveRecord::Relation::ActiveRecord_Relation_Airport:0x007fd89ed33b18>
'Where' returns an array, and you are calling an instance method on it.
Try
x = Airport.where(code: "LAX").first
The problem is the method you are using.
Model#where does not return an object (as expected from active record) for you to work with, instead you should use Model#find_by(attribute: expression)
In your case use:
x = Airport.find_by(code: "LAX")
where(opts = :chain, *rest) public
Returns a new relation, which is the result of filtering the current relation according to the conditions in the arguments.
i.e.
x = Airport.where(code: "LAX")
Airport Load (2.9ms) SELECT "airports".* FROM "airports" WHERE "airports"."code" = 'LAX'
=> #<ActiveRecord::Relation [#<Airport id: 3533, code: "LAX", lat: 33.9456, lon: -118.391, name: "Los Angeles International Airport", city: "Los Angeles", state: "California", country: "United States", woeid: 12520706, tz: "America/Los_Angeles", phone: "", email: "", url: "", runway_length: 12091, elev: 126, icao: "KLAX", direct_flights: 200, carriers: 99, created_at: "2015-08-06 19:10:03", updated_at: "2015-08-17 03:05:53", current_high_temp: 84, current_low_temp: 70>]>
you notice that the Object type is ActiveRecord::Relation instead of Airport and the Airport object is wrapped with array literals [] however, the collection type is not array. So,
Either you want to use
x = Airport.where(code: "LAX").first
or
x = Airport.where(code: "LAX")[0] # not recommended
If 'code' is a unique key the you might use
# this gives the first airport with code = 'LAX'
x = Airport.find_by_code("LAX")
or if you want to see the current_high_temp of all airports then you might want to do this
x = Airport.where(code: "LAX").pluck('current_high_temp')
pluck(*column_names) public Use pluck as a shortcut to select one or
more attributes without loading a bunch of records just to grab the
attributes you want.
Person.pluck(:name)
instead of
Person.all.map(&:name)

Ruby on Rails: Check whether a word is matched to any attributes in database

I am doing my Ruby on Rails project now. PostgreSQL is used as database.I have a table called pets, where stores all pets information(name, gender, age, etc.), which are shown as follows.
{Pet id: 1, name: "Jean", gender: "Female", pet_type: "Cat", age: "0", body_weight: 1, breed: "Abyssinian", created_at: "2015-04-26 23:50:01", updated_at: "2015-04-26 23:50:01"}
{Pet id: 2, ...}
...
{Pet id: 10, ...}
Now I am going to check whether there is a Abyssinian breed cat in table pets. If there is, return the Pet id, otherwise return "no such cat found".
Is there anyone know how to do this? Thanks in advance.
To find the first pet where breed == "Abyssinian":
pet = Pet.find_by(breed: "Abyssinian", pet_type: "Cat")
So, to combine that with your required logic:
pet = Pet.find_by(breed: "Abyssinian", pet_type: "Cat")
output = pet ? pet : "no such cat found"
You could simply this even further to:
output = Pet.find_by(breed: "Abyssinian", pet_type: "Cat") || "no such cat found"
Is "breed" a field in the pets table? If so, you could do something like:
if Pet.exists?( breed: "Abyssinian" )
x = Pet.where( breed: "Abyssinian" )
else
x = "No such cat found"
end
The danger in this is that there could be multiple Pets returned. If you want to find one and only one, you could do
if Pet.where( breed: "Abyssinian" ).count == 1
instead.
REVISION
#infused's answer is more succinct, I would encourage an implementation similar to his, assuming a breed column exists.

semicolon as statement separator in Rails Console

The Rails console doesn't seem to like multiple ruby statements on the same line separated by a semicolon. Whenever I do this, the next line starts with ?> and I find that only the first statement was executed. Do you have to put each statement on a separate line?
>> user = User.new
user = User.new
=> #<User id: nil, username: "", hashed_password: "", first_name: "", last_name: "", email: "", display_name: "", user_level: 0, created_at: nil, updated_at: nil, posts_count: 0>
>> user.username = "John"; hashed_password = "John"; first_name = "John"; last_name = "coltrane"; email = "John#coltrane.com"; display_name = "Johndispay"; user_level = 9;
user.username = "John"; hashed_password = "John"; first_name = "John"; last_name = "coltrane"; email = "John#coltrane.com"; display_name = "Johndispay"; user_level = 9;
?> user.save
user.save
=> true
Everything except user.username = "John"; was ignored
You need to say "user." so Ruby knows you mean to call the attribute assignment methods of the instance of user. Otherwise, you are just setting local variables called "hashed_password", etc.
>> user.username = "John"; user.hashed_password = "John"; user.first_name = "John"; user.last_name = "coltrane"; user.email = "John#coltrane.com"; user.display_name = "Johndispay"; user.user_level = 9;
Although, you could just pass a hash of the attributes you want to set on the new instance, like so
>> user = User.new(:username => "John", :hashed_password => "John", ...
It's the trailing ; on your input. When you put a ';' on the end IRB will assume you want to add another statement. If you leave it off, it will evaluate all the statements and return the return value of the last one.
Sometimes if the method I'm calling is going to return a large array I will do something like this...
a = Account.entries; a.size
This will save the values I need and just output the size of the array instead of trying to dump it to the console, which can take a long time if it's large.
are you sure you didn't mean
user.username = "John"; user.hashed_password = "John";
i tried
>> a = 1; b= 2
=> 2
>> a
=> 1
>> b
=> 2
when something doesn't work, you can use one rule: always reduce it to the simplest case.

Resources