I have a model called SystemState. Following is the migration that created this table:
create_table :system_states do |t|
t.string :code
t.timestamps
end
But, even if code column is of string type, when I do the following:
> SystemState.first
> #<SystemState id: 1, code: 0, created_at: "2017-03-14 10:19:45", updated_at: "2017-03-14 10:28:33">
> SystemState.find(1).update_attributes(code: "system_alert_notification")
> SystemState.first
> #<SystemState id: 1, code: 0, created_at: "2017-03-14 10:19:45", updated_at: "2017-03-14 10:29:43">
As can be seen, it always updates it as 0(integer).
Is the column name reserved or something? Keen to know the cause of above.
Here are some possibilities :
1) May be code is a reserved word in mysql
2) Also, I'm sure, the column in your db is of integer type. Change it to string and it should work.
Related
I am using jbuilder in rails to generate some JSON in a rails app.
In my models, 'od_items' belong to 'od', and 'ods' belong to 'sophead'.
I want to display each 'od' of the 'sophead', and then nested under each of these, I want to display each of the 'od_items' that belong to the 'od'.
Here is my code so far:
json.ods #sophead.ods do |od|
json.od od
json.od_items od.od_items do |od_item|
json.od_item od_item
end
end
This is outputting the following JSON:
ods: [
{
od: {
id: 51,
sophead_id: 386,
created_at: "2018-03-21T15:28:48.802Z",
updated_at: "2018-03-21T15:28:48.802Z",
status: "Open"
},
od_items: [
{
od_item: {
id: 285,
od_id: 51,
qty: "1.0",
part: "CARRIAGE CHARGE",
description: "Simpson Carriage Charge",
created_at: "2018-03-21T15:28:48.823Z",
updated_at: "2018-03-21T15:28:48.823Z"
}
},
{
od_item: {
id: 284,
od_id: 51,
qty: "1.0",
part: "MISCELLANEOUS",
description: "Split Box Charge",
created_at: "2018-03-21T15:28:48.816Z",
updated_at: "2018-03-21T15:28:48.816Z"
}
}
]
}
],
The problem is that I want 'od_items' to be nested inside the 'od' that it relates to, instead it appears next to it.
This should be pretty simple to sort out, but I cant find anything online.
(First question on Stack overflow - Thanks very much in advance)
If your #sophead.ods is a collection of hashes, you can easily achieve it merging the od element with its od_items:
json.ods #sophead.ods do |od|
json.od od.merge(od_items: od.od_items)
end
Since it seems that these are ActiveRecords:
json.ods #sophead.ods do |od|
json.od od.as_json.merge(od_items: od.od_items.map(&:as_json))
end
According to the README, another way to obtain the same result is to use json.merge!:
json.ods #sophead.ods do |od|
json.od do
json.id od.id
json.sophead_id od.sophead_id
json.created_at od.created_at
json.updated_at od.updated_at
json.status od.status
json.merge! { od_items: od.od_items.as_json}
end
Another approach which assures better performances would be to use ActiveModelSerializer instead.
class OdSerializer < ActiveModelSerializers::Model
attributes :id, :sophead_id, :created_at, :updated_at, :status
has_many :od_items, serializer: OdItemSerializer
end
class OdItemSerializer < ActiveModelSerializers::Model
attributes :id, :od_id, :qty, :part, :description, :created_at, :updated_at
end
# And in the controller
render json: #sophead.ods, each_serializer: OdSerializer
In my controller, I need to pluck a single, matching integer value and then create a record with that value in another table. In action, it looks like this:
if Participation.where(ranking: "1")
first = PointsAllocation.where(game_id: params[:game_id]).where(place: "1").pluck(:points)
Stack.create(game_id: params[:game_id], user_id: current_user.id, chips: first)
else
end
I have tested in the console that the first variable is definable. If I run PointsAllocation.where(game_id: "1").where(place: "1").pluck(:points), it will return:
SELECT "points_allocations"."points" FROM "points_allocations" WHERE "points_allocations"."game_id" = 1 AND "points_allocations"."place" = 1
=> [10]
Ok, so it is correctly plucking what looks like an integer value for Points. I then want to use this points value and send it to the Chips column in the Stack table. When I run this, it will add a nil record even though first is defined, like so:
<Stack id: 1, game_id: 1, user_id: 1, chips: nil>
In troubleshooting, I thought maybe the issue here is that even though it looks like an integer (and Chips, I should add, is a t.integer attribute), maybe it's accidentally a string or something from pluck. So let's map this to an integer to be safe by adding map(&:to_i) after the pluck.
When I do that, it gets weirder, as it now returns:
<Stack id: 9, game_id: 1, user_id: 1, chips: 0>
So when I convert it to an integer, it changes 10 to a 0 and adds it to the table.
Where am I going wrong?
You may resolve it loading only one object instead ActiveRecord::Association:
first = PointsAllocation.where(game_id: params[:game_id]).where(place: "1").first
points = first.points
Stack.create(game_id: params[:game_id], user_id: current_user.id, chips: points)
Problem is that AR trying convert incorrect values if they type different with column type:
Stack.create(chips: 10)
#=> <Stack id: ..., chips: 10>
Stack.create(chips: [10])
#=> <Stack id: ..., chips: nil>
Stack.create(chips: "10")
#=> <Stack id: ..., chips: 10>
Stack.create(chips: "first")
#=> <Stack id: ..., chips: 0>
Ok. Asked this question yesterday and since started a whole new rails app to see if starting from scratch helps.
Here's how this app works. A user will create a new countertop and enter their zip code, the countertop size and the type of countertop. Possible countertop types are stored in a model called "Countertype". Users select the countertype through a collection_select method, which lists all the entries in the Countertype table. The responses to this Countertop form are saved in a Countertop table, which has a "countertop_id" integer column.
When the user lands on the Show and then the Index page, I'd like the name of the countertype to be visible instead of the integer.
How do I do this? It's killing me.
Here's my schema:
create_table "countertops", force: :cascade do |t|
t.string "counterzip"
t.string "countersize"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "countertype_id"
end
create_table "countertypes", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Here's my index and show
def index
#countertops = Countertop.all
#countertops = Countertop.includes(:countertype).all
end
def show
#countertops = Countertop.all
#countertops = Countertop.includes(:countertype).all
end
Countertop.rb:
class Countertop < ActiveRecord::Base
has_one :countertype
end
Countertype.rb
class Countertype < ActiveRecord::Base
belongs_to :countertop
end
Show:
<p>
<strong>Counter Type:</strong>
<%= #countertop.countertype.name %>
</p>
Index:
<% #countertops.each do |countertop| %>
<tr>
<td><%= countertop.counterzip %></td>
<td><%= countertop.countertype.name %>
Here's a readout from my console for both tables.
Countertop.last
Countertop Load (0.2ms) SELECT "countertops".* FROM "countertops" ORDER BY "countertops"."id" DESC LIMIT 1
=> #<Countertop id: 1, counterzip: "19111", countersize: "100", created_at: "2015-10-01 20:44:29", updated_at: "2015-10-01 20:44:29", Countertype_Id: 1>
2.2.1 :029 >
Countertype.last
Countertype Load (0.7ms) SELECT "countertypes".* FROM "countertypes" ORDER BY "countertypes"."id" DESC LIMIT 1
=> #<Countertype id: 1, name: "Granite", created_at: "2015-10-01 20:15:12", updated_at: "2015-10-01 20:15:12">
Heres's the error message:
SQLite3::SQLException: no such column: countertypes.countertop_id: SELECT "countertypes".* FROM "countertypes" WHERE "countertypes"."countertop_id" = ? LIMIT 1
Changing the show to <%= #countertops.countertype_id %> displays a "1".
What do I need to fix to have it display "Granite" instead of "1" ??
Thanks!!
It looks like you have your associations backwards in the two models. belongs_to should be listed in the model whose table contains the association column (countertype_id in this case). has_one relies on the associated model to have this column.
A couple additional observations:
According to the output from Countertop.last, Countertype_Id has uppercase characters. This might not cause immediate problems with sqlite, but it may be worth changing to avoid any future problems, as Rails will assume column names are always downcased unless explicitly told otherwise.
Your #show controller method has #countertops defined (plural), but the show view uses just #countertop.
in Rails 3 app I have table subscription_schedules, in which there is a column of 'time' type
example record lokks like this:
#<Subscription::Schedule id: 3504, subscription_id: 4961, scheduled_at: "2000-01-01 01:11:00", primary: true, created_at: "2015-09-28 01:13:34", updated_at: "2015-09-28 01:13:34", active: true>
What I want to do is to convert scheduled_at to datetime. I decided to add new column 'temp_scheduled_at', save all 'scheduled_at' to it, change 'scheduled_at' to datetime with change_column() method , and later move whats in 'temp_scheduled_at' to 'scheduled_at'.
It looks like this:
add_column :subscription_schedules, :temp_scheduled_at, :datetime
Subscription::Schedule.select {|s| s.subscription}.each do |schedule|
schedule.temp_scheduled_at = schedule.scheduled_at
schedule.scheduled_at = nil
begin
schedule.save!
rescue => e
puts schedule.id
end
end
change_column :subscription_schedules, :scheduled_at, :datetime
Unfortunately thats where the troubles start. After calling Subscription::Scheudule.all later on, I get
Invalid date in field 'scheduled_at': 2001-00-00 00:00:00
I really have no idea what is causing this error, before changing column type record with 'invalid date' looked like this:
#<Subscription::Schedule id: 2555, subscription_id: 4102, scheduled_at: "2000-01-01 05:00:00", primary: true, created_at: "2015-06-23 16:12:01", updated_at: "2015-06-23 16:12:01", active: true>
I suggest you to use it in mysql query. You can change time to datetime in mysql query and refered as new column name. Its very easy compare to progrmming way. for ex-
select schedule_at, now() as temp_scheduled_at from tablename;
You can read more date time function here
Model for Plugin:
class Plugin < ActiveRecord::Base
has_many :vulns
end
Model for Vuln:
class Vuln < ActiveRecord::Base
belongs_to :plugin
end
Table for Plugin:
create_table "plugins", force: true do |t|
t.string "name"
end
Table for Vuln:
create_table "vulns", force: true do |t|
t.string "title"
t.integer "plugin_id"
t.string "vulnerability_type"
t.string "fixed_in"
end
When I use rails console using rails c and enter Plugin.select("*").joins(:vulns) it only grabs data from the Plugin table
#<ActiveRecord::Relation [#<Plugin id: 1, name: "xxx">, #<Plugin id: 2, name: "xxx">
This is the query:
SELECT * FROM `plugins` INNER JOIN `vulns` ON `vulns`.`plugin_id` = `plugins`.`id`
However, when I execute this query in mysql, it shows all content from vulns and plugins like its supposed to. For every plugin there is atleast one or more vuln in the database.
So here's the question: How do I get it to fetch content from both tables (plugins and vulns) instead of just plugins?
The vulns values are there, it's just not shown because you are using Plugin model to select, i.e. Plugin.select("*").joins(:vulns).
If you did the following, you will get the value:
> plugin = Plugin.select("*").joins(:vulns)
> plugin.first.title
=> "mytitle"
Because you are querying through Plugin model, you'll see Plugin object.
Another way to test this would be by doing the following:
> plugin = Plugin.select([:name, :title]).joins(:vulns)
=> #<ActiveRecord::Relation [#<Plugin id: 1, name: "xxxx">]>
# It won't show you title even though it's there
> plugin.title
=> "mytitle"