I'm new to ruby. So I'm confused by the following lines of code:
class CreateProducts < ActiveRecord::Migration
def self.up
create_table :products do |t|
t.string :title
t.text :description
t.string :image_url
t.decimal :price, :precision => 8, :scale => 2
t.timestamps
end
end
def self.down
drop_table :products
end
end
one of the lines makes me most confused is :
t.string :title
I just can't understand it. So could any of you give me some hint on which part of ruby grammar I need to read in order to understand this single line of code? thanks in advance.
This is just normal Ruby messaging syntax.
t.string :title
means
dereference the block local variable t
send the message :string to the object referenced by t and pass the literal symbol :title as the only argument
I'm guessing a bit here, but as a basis for exploration
:title is a Ruby "symbol" - basically a hack to provide higher-efficiency string-like constants - so t.string :title is a bit like calling a t.string("title") in more popular OO languages, and given you seem to be declaring a record structure for the database, I'd say that's adding a field effectively "called" title with type "string".
You will find the answer within Why's poignant guide to Ruby
P.S. It's spelt grammar, but for code we'd usually use the word 'syntax'. :)
Check this out this might prove to be very helpful
This file is called migration file it creates the backend for your app
Another link
to fully understand that file, you need to understand classes, inheritance, modules, method calling, blocks and symbols.
Related
I'm new to rails, and I'm currently trying to develop an API based app using Rails 5, on one of my controllers I have a function to filter the allow parameters like so
def provider_params
params.require(:provider).permit(:name, :phone, :email, :website, :address, :provider_id, :bio, :specialty_ids => [])
end
Then posting from Paw I noticed that the arguments that are not attributes of the table are no included in provider_params, the parameter I'm supposed to receive is an array, which is defined by a HABTM relation-ship.
This is how my models look like
specialty.rb
class Specialty < ApplicationRecord
has_and_belongs_to_many :providers
end
provider.rb
class Provider < ApplicationRecord
has_and_belongs_to_many :specialties
end
And this is how the join table was created via migration
class CreateProvidersSpecialties < ActiveRecord::Migration[5.0]
def change
create_table :providers_specialties, :id => false do |t|
t.integer :provider_id
t.integer :specialty_id
end
add_index :providers_specialties, :provider_id
add_index :providers_specialties, :specialty_id
end
end
The JSON I'm posting
{
"name": "the name",
"specialty_ids": [
1,
2
]
}
So as I mentioned, the array specialty_ids doesn't seem to be coming through, and even if it did, I suspect there's still something else I need to do in order for rails to insert the content of specialty_ids in the ProvidersSpecialties Table
So the problem was finally solved by removing the requir call from the method provider_params, since I wasn't wrapping the json-payload in a provider key. Apparently once you add the require(:key) call you would only be able to add parameters that belong to the Model, which is weird since an error should be raised when the key is not present, what was the case with my payload, lacking the provider key.
I have this json file that I want to put into a database, here it is, http://pastebin.com/m3GsTfdi
This is the migration file for the table that I want to store this information in;
create_table :characters do |t|
t.string :name
t.string :region
t.string :realm
t.integer :class
t.integer :race
t.integer :level
t.integer :achievementPoints
t.string :items
t.string :stats
t.string :hunterPets
t.string :talents
t.string :progresison
t.timestamps null: false
end
And this is how I'm trying to insert a character through seed.rb
JSON.parse(open("#{Rails.root}/app/assets/seed/netfive.json").read).each do |chardata|
Character.create(chardata)
end
However I'm getting the error
"ArgumentError: When assigning attributes, you must pass a hash as an argument."
when I run rake db:seed.
How should I fix it? I'm thinking it's something to do with I'm trying to save an array where it should be a string, but I'm not sure how else to do it.
Edit:
I managed to fix it doing the seed like this instead;
char_data = JSON.parse(File.read("#{Rails.root}/app/assets/seed/netfive.json"))
Character.new({
name:char_data['name'],
realm:char_data['realm'],
charClass:char_data['class'],
race:char_data['race'],
level:char_data['level'],
achievementPoints:char_data['achievementPoints'],
items:char_data['items'],
stats:char_data['stats'],
hunterPets:char_data['hunterPets'],
talents:char_data['talents'],
progression:char_data['progression'],
}).save
I did also use serialization that was previously linked in a comment.
Thank for the help!
When you loop though the JSON, you will be looping through each key and value within the JSON. This is not what you want. You want to create one character from the data.
It would look something like this:
char_data = JSON.parse(File.read("#{Rails.root}/app/assets/seed/netfive.json"))
Character.create char_data
You will have to be careful with data types when you are doing this. i.e. You might have an issue saving items as a String. I would instead look at serializing that data.
Here is a reference for serialization: http://apidock.com/rails/ActiveRecord/AttributeMethods/Serialization/ClassMethods/serialize
In the console of my application I get "undefined method `each' for true:TrueClass" when attempting to set a Boolean to true or false.
For instance if I do
Man.create(guy: true) # or
Man.create(:guy => true) # etc
I have not worked on this application for several months and I believe everything was working fine before I stopped work on it. I am pretty new to Ruby and have limited programming knowledge so any help is much appreciated. creating rows and providing only string or integer values works fine. I am using an SQLite3 database if that matters.
guy is a Boolean
class AddMan < ActiveRecord::Migration
def change
create_table :men do |t|
t.boolean :guy
t.boolean :girl
t.boolean :dude
t.boolean :lady
t.boolean :albert
t.timestamps
end
end
end
class Man < ActiveRecord::Base
has_many :guys
has_many :girls
end
This:
has_many :guys
has_many :girls
assumes, by Rails convention, the presence of Integer columns :guy_id and girl_id, which should be foreign keys into the guys and girls tables, respectively. These are not present in your schema, so I assume that's the root cause of the error you're seeing.
In general, try avoiding column names that may be in conflict with other models (I assume you have models named Guy and Girl. Try renaming your boolean columns to something like is_guy and is_girl.
From your Man Model I assumes that you have guys and girls different tables. And from your console it seems that you want to assign value to Man table's guy attribute.
If this is the case then you can assign value to your Man table's guy attribute like
man = Man.new
man.guy = true
I'm wondering if I miss a way to avoid repeat validation code in my Sequel::Model#validate subclass method since I've already put all constraints into my migration file.
Here's a simple example of what I'm talking about :
Sequel.migration do
change do
create_table :users do
primary_key :id
String :name, :null => false, :unique => true
end
end
end
class User < Sequel::Model
def validate
super
validates_presence :name
validates_unique :name
validates_type String :name
end
end
It seems very painful and errors prone to have to repeat all the constraints in the validate method. Did I miss something or there's no other way to do that ?
Any advice will be appreciated, thanks
Sequel has some nice plugins and extensions.
Sequel::Model.plugin(:auto_validations)
Sequel::Model.plugin(:constraint_validations)
and
DB.extension(:constraint_validations)
auto_validations
The auto_validations plugin automatically sets up three types of
validations for your model columns:
type validations for all columns
not_null validations on NOT NULL columns (optionally, presence
validations)
unique validations on columns or sets of columns with unique indexes
See http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/AutoValidations.html
constraint_validations
The constraint_validations extension is designed to easily create
database constraints inside create_table and alter_table blocks. It
also adds relevant metadata about the constraints to a separate table,
which the constraint_validations model plugin uses to setup automatic
validations.
See http://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/constraint_validations_rb.html
and
http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/ConstraintValidations.html
Your example would look like this
Sequel::Model.plugin(:auto_validations)
Sequel::Model.plugin(:constraint_validations)
Sequel.migration do
up do
extension(:constraint_validations)
create_table :users do
primary_key :id
String :name, :null => false, :unique => true
validate do
presence :name,
name: :presence_name
end
end
end
down do
extension(:constraint_validations)
drop_table(:users)
end
end
class User < Sequel::Model
end
I think, it's normal. Don't worry.
I have a simple case, involving two model classes:
class Game < ActiveRecord::Base
has_many :snapshots
def initialize(params={})
# ...
end
end
class Snapshot < ActiveRecord::Base
belongs_to :game
def initialize(params={})
# ...
end
end
with these migrations:
class CreateGames < ActiveRecord::Migration
def change
create_table :games do |t|
t.string :name
t.string :difficulty
t.string :status
t.timestamps
end
end
end
class CreateSnapshots < ActiveRecord::Migration
def change
create_table :snapshots do |t|
t.integer :game_id
t.integer :branch_mark
t.string :previous_state
t.integer :new_row
t.integer :new_column
t.integer :new_value
t.timestamps
end
end
end
If I attempt to create a Snapshot instance in rails console, using
Snapshot.new
I get
(Object doesn't support #inspect)
Now for the good part. If I comment out the initialize method in snapshot.rb, then Snapshot.new works. Why is this happening?
BTW I am using Rails 3.1, and Ruby 1.9.2
This is happening because you override the initialize method of your base class (ActiveRecord::Base). Instance variables defined in your base class will not get initialized and #inspect will fail.
To fix this problem you need to call super in your sub class:
class Game < ActiveRecord::Base
has_many :snapshots
def initialize(params={})
super(params)
# ...
end
end
I had this symptom when I had a serialize in a model like this;
serialize :column1, :column2
Needs to be like;
serialize :column1
serialize :column2
I ran into this issue when I used an invalid association name in a joins.
For example,
Book.joins(:authors).first
Should be
Book.joins(:author).first
Assuming a Book model belongs_to an Author model.
This can also happen when you implement after_initialize, particularly if you are attempting to access attributes which were not included in your select. For instance:
after_initialize do |pet|
pet.speak_method ||= bark # default
end
To fix, add a test for whether the attribute exists:
after_initialize do |pet|
pet.speak_method ||= bark if pet.attributes.include? 'speak_method' # default`
end
I'm not sure exactly why, but I got this error when I accidentally misspelled 'belongs_to' as 'belong_to' in the associated class definition.
I believe you forgot to
rails db:migrate
Try calling .valid? on the new object to see if you can get a more helpful error.
In my case, I got this error from a block of code that creates a new instance of one of my models and assigns values to its fields. It turns out that my code was assigning a value to one of the fields that Rails couldn't match with that field's type. Calling valid? on the new object gave me a more helpful error (undefined method `to_f' for #<MatchData...).
I ran into this problem after trying to integrate devise authentication with an existing User model, I solved it by running command below:
$spring stop
Don't know the exact cause but hope it helps someone.
This is a misleading and nonspecific error. For instance, I just got it because I made a scope like this:
scope :posted, -> { where('posted_on_date <= ?', Date.today) }
when it should have been:
scope :posted, -> { where('post_on_date <= ?', Date.today) }
In my case, this was due to my mistakenly using the posted_on_date attribute.
I get this problem if the model contains an after_find.
The same error if you put the attribute type wrong:
attribute :publicar, :integer, default: true
instead of
attribute :publicar, :boolean, default: true
I was getting this error when running an ActiveRecord .where clause/method.
It was simply because there was a typo in the column name. Once I fixed the typo the query worked exactly as expected.
Wrong:
Package.where(scrape_nunber: 2)
Right (fixed typo in column name, and it works now):
Package.where(scrape_number: 2)
Just double check there isn't a typo in your column name(s) in the where clause.