I am totally new to ruby. I am trying to make a RESTful service for task tracking application. I researched and found Sinatra better for the job than rails. So I am using Sinatra and ActiveRecord. I am following Up and Running With Sinatra and ActiveRecord. I will be creating the client application in .NET using Restsharp. But this is all about server side.
This is the migration I have created
class CreateTasksPeopleDocumentsAndComments < ActiveRecord::Migration
def self.up
create_table :tasks do |t|
t.string :name
t.string :task_status
t.string :task_type
t.text :description
t.text :analysis
t.text :investigation
t.integer :developer_id
t.integer :reviewer_id
t.date :open_date
t.date :analysis_date
t.date :promotion_date
t.date :review_date
t.date :correction_date
t.date :collection_date
t.date :closed_date
t.date :modified_date
t.date :target_date
end
create_table :people do |t|
t.string :name
t.string :trigram
t.string :state
t.string :level
end
create_table :documents do |t|
t.string :name
t.binary :data
t.string :path
t.integer :task_id
t.integer :developer_id
end
create_table :comments do |t|
t.text :comment
t.datetime :comment_timestamp
t.integer :person_id
t.integer :task_id
t.integer :comment_id
end
end
def self.down
drop_tables :tasks
drop_tables :people
drop_tables :documents
drop_tables :comments
end
end
And the Main App.rb
class Person < ActiveRecord::Base
end
class Developer < Person
has_many :tasks
end
class Reviewer < Person
has_many :tasks
end
class Task < ActiveRecord::Base
belongs_to :developer
belongs_to :reviewer
has_many :documents
end
class Document < ActiveRecord::Base
belongs_to :task
belongs_to :developer
end
class Comment < ActiveRecord::Base
belongs_to :task
has_many :comments
end
get '/' do
"Hola World!"
end
get '/tasks' do
Task.all.to_json
end
get '/people' do
Person.all.to_json
end
get '/person/:id' do
Person.where(["id = ?", params[:id]]).to_json
end
get '/task/:id' do
Task.where(["id = ?", params[:id]]).to_json
end
get '/document/:id' do
Document.where(["id = ?", params[:id]]).to_json
end
get '/task/:id/documents' do
# Task.where(["id = ?", params[:id]]).document.all.to_json
# Document.where(["task_id = ?", params[:id]]).all.to_json
Task.find(params[:id]).documents.all.to_json
end
get '/make' do
person1 = Person.create(
:name => "AEonAX",
:trigram =>"anx",
:state => "Active",
:level => "Master"
)
person2 = Person.create(
:name => "XEonAX",
:trigram =>"xnx",
:state => "Inactive",
:level => "User"
)
person3 = Person.create(
:name => "ZEonAX",
:trigram =>"znx",
:state => "Active",
:level => "User"
)
person4 = Person.create(
:name => "LEonAX",
:trigram =>"lnx",
:state => "Inactive",
:level => "Master"
)
task1 = Task.create(
:name => "IR-000001V0R2000",
:description => "The Very First Incident Report",
:task_status => "Opened",
:task_type => "Internal",
:developer_id => person2.id,
:reviewer_id => person1.id
)
task2 = Task.create(
:name => "IR-000002V0R2000",
:description => "Second Incident Report",
:task_status => "Tech. Anal.",
:task_type => "External",
:developer_id => person2.id,
:reviewer_id => person1.id
)
task3 = Task.create(
:name => "IR-000003V0R2000",
:description => "Another Incident Report",
:task_status => "Under Corr.",
:task_type => "External",
:developer_id => person3.id,
:reviewer_id => person1.id
)
document1 = Document.create(
:name => "FirstDoku",
:path => "\\XEON-NB\Test\FiddlerRoot.cer",
:task_id => task1.id,
:developer_id => task1.developer.id,
:data => Task.all.to_json #SomeBinaryData
)
end
Currently this code only reads data. I have not started writing of data.
Basically the relations are like for a task there will be a developer and reviewer. It will have documents attached to it. It will also have comments.
Comments can be on the task or in reply to a comment.
As you can see I have declared a Person class and derived Developer and Reviewer from it. Is it the right way? Any other suggestions are welcome. Even suggestions to use other frameworks are accepted.
Related
I am new to Rails and I am trying to get my application running.
My UserMigration.rb file contains:
class UserMigration < ActiveRecord::Migration
def self.up
if (!ActiveRecord::Base.connection.table_exists? :users)
drop_table :users
create_table :users do |t|
t.string :email
t.string :first
t.string :last
t.string :password
t.string :username
t.integer :created_by
t.string :bio #Newly added
t.integer :id #Newly added
t.string :photoURL #Newly added
end
add_index :users, :email
end
if (Models::Persistence::User.count == 0)
Models::Persistence::User.create({:email => 'testuser#my.com',
:username => 'testuser#my.com',
:first => 'Test',
:last => 'User',
:password => 'Test123',
:bio => "User, student",
:id => "1",
:photoURL => "http://link",
:created_by => 1})
And my models User.rb file contains:
module Models
module Persistence
class User < ActiveRecord::Base
validates :bio, :presence => true, length: {minimum: 150}
I am working off an example and I just recently added the three extra fields in the users table (bio, id and photoURL). I keep getting this error when I run my tests with the newly added fields on the db:
undefined method `bio' for #<Models::Persistence::User:0x007f8c04ae6838>
Any pointers on where I could start debugging this from? Thanks!
I have two classes in ruby:-
class Role < ActiveRecord::Base
# attr_accessible :title, :body
acts_as_authorization_role :subject_class_name => 'User', :join_table_name => "roles_users"
end
and
class User < ActiveRecord::Base
acts_as_authentic
acts_as_authorization_object :role_class_name => 'Role', :subject_class_name => 'User'
acts_as_authorization_subject :association_name => :roles , :join_table_name => 'roles_users'
has_one:employee_detail ,:foreign_key => "User_id"
end
and migration files are:-
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :crypted_password
t.string :password_salt
t.string :persistence_token
t.timestamps
end
end
end
class CreateRoles < ActiveRecord::Migration
def change
create_table "roles" , :force => true do |t|
t.string :name , :limit => 40
t.string :authorizable_type, :limit => 40
t.integer :authorizable_id
t.timestamps
end
end
end
class RolesUsers < ActiveRecord::Migration
def change
create_table "roles_users", :id => false, :force => true do |t|
t.references :user
t.references :role
end
end
end
i have user id and want to retrieve role id, but not able to query intermediate table. can anyone provide some solution for this. thnks
It's clear that your user is going to have multiple roles
You can define an habtm relation in user for for role and get retrive roles roles like following
class User < ActiveRecord::Base
acts_as_authentic
acts_as_authorization_object :role_class_name => 'Role', :subject_class_name => 'User'
acts_as_authorization_subject :association_name => :roles , :join_table_name => 'roles_users'
has_one:employee_detail ,:foreign_key => "User_id"
has_and_belongs_to_many :roles
end
And retrieve roles for a user like below
user = User.find user_id
user.roles # this will give you roles array
role_ids = user.roles.map { |r| r.id } # if you only want array of ids
I am trying to create a numerous amount of tags inside of my database, does anyone know how to do this with the gem acts-as-taggable-on?
Products table:
create_table :products do |t|
t.string :name
t.date :date
t.decimal :price, :default => 0, :precision => 10, :scale => 2
t.integer :user_id
end
and the :tag_list field is a virtual column created by the migration of ActsAsTaggableOn:
class ActsAsTaggableOnMigration < ActiveRecord::Migration
def self.up
create_table :tags do |t|
t.string :name
end
create_table :taggings do |t|
t.references :tag
# You should make sure that the column created is
# long enough to store the required class names.
t.references :taggable, :polymorphic => true
t.references :tagger, :polymorphic => true
t.string :context
t.datetime :created_at
end
add_index :taggings, :tag_id
add_index :taggings, [:taggable_id, :taggable_type, :context]
end
def self.down
drop_table :taggings
drop_table :tags
end
end
This is my :tag_list field in my products/form.html.erb
<div class="field">
<%= f.label :tag_list %>:
<%= f.text_field :tag_list %>
</div>
I tried to do something like this....
Product.create([
{:tag_list => 'Foods'},
{:tag_list => 'Electronics'},
{:tag_list => 'Pizza'},
{:tag_list => 'Groceries'},
{:tag_list => 'Walmart'},
{:tag_list => 'Apples'},
{:tag_list => 'Oranges'} ])
But my lack of RoR skill tells me this is the wrong way and that i need help, any suggestions?
You can try this in your seeds.rb:
list = ['tag 1', 'tag 2', ...]
list.each do |tag|
ActsAsTaggableOn::Tag.new(:name => tag).save
end
Obviously substitute the values of the list array for your desired tags.
Note: this will just populate the tags table. I hope that is what you were looking for.
Hope this helps!
You might create some test products in your seeds file using something like this:
unless Rails.env.production?
1..20.times.each do |n|
Product.create(
name: "Some product #{n}",
date: Date.today - n.days,
price: 1_000_000 + n,
user: User.first
)
end
end
So you could seed tags by doing this
# ...
product = Product.create(
# ...
)
product.tag_list.add "tag1", "tag2"
product.save
# ...
Or
# ...
Product.create(
# ...
).tap do |product|
product.tag_list.add "tag1", "tag2"
product.save
end
# ...
I'm trying to figure out if there is a way to do this in Rails more efficiently.
There is kind of a long setup for the question, so please bear with me.
Let's say I have models Customer, Phone, Address
Here are sample migrations to give you an idea:
class CreatePhones < ActiveRecord::Migration
def self.up
create_table :phones do |t|
t.integer :country_prefix, :limit => 3
t.integer :area_prefix, :limit => 5
t.integer :number, :limit => 7
t.integer :category_id
t.references :phonable, :polymorphic => true
t.timestamps
end
end
end
class CreateAddress < ActiveRecord::Migration
def self.up
create_table :addresses do |t|
t.string :address_line_1
t.string :address_line_2
t.string :address_line_3
t.string :city
t.string :state
t.string :zip
t.string :country
t.string :attn
t.integer :category_id
t.references :addressable, :polymorphic => true
t.timestamps
end
end
end
class CreateCategories < ActiveRecord::Migration
def self.up
create_table :categories do |t|
t.string :name
t.string :code
t.integer :category_id # Every subcategory has a category: i.e. phone has work, fax,mobile
t.timestamps
end
end
end
class CreateCustomers < ActiveRecord::Migration
def self.up
create_table :customers do |t|
t.string :code , :limit => 20 , :null => false
t.string :name , :null => false
t.string :billing_name
t.integer :preferred_shipping_method_id
end
end
Here are models and relations:
class Customer < ActiveRecord::Base
belongs_to :preferred_shipping_method , :class_name => "Category", :foreign_key => :preferred_shipping_method_id
has_many :addresses, :as => :addressable, :include => :category, :dependent => :destroy
has_many :phones, :as => :phonable, :include => :category, :dependent => :destroy
end
class Category < ActiveRecord::Base
has_many :addresses
has_many :phones
has_many :customer_by_shipping_methods, :class_name => "Customer", :foreign_key => :preferred_shipping_method_id
has_many :subcategories, :class_name => "Category", :foreign_key => :category_id
belongs_to :category, :class_name => "Category"
end
class Address < ActiveRecord::Base
belongs_to :category
belongs_to :addressable, :polymorphic => true
end
class Phone < ActiveRecord::Base
belongs_to :category
belongs_to :phonable, :polymorphic => true
end
Here is a question.
Let's say I have a customer record with a bunch of phone (mobile, work) and addresses (billing, shipping).
old = Customer.where(:code => "ABC").first
Then I'm creating or importing (from a legacy DB) another customer object
new = Customer.new
new.code = "ABC"
new.phones.build(:number => "12345567")
etc.
Then I want to compare old customer info to the new customer info and based on that update old customer info.
Like so :
if old.eql?(new) # this should compare not only, name & code and such but also polymorphic associations
old.update_with(new) # this should update old info attributes with new if there is new info, or if update / add to one of the associations
old.save #
else
new.save
end
So the question is is there any CONVENTIONAL way in Rails 3 to do what I describe in comments?
Right now I'm overriding hash & eql? methods which is fine for comparison. But to update each attribute and each associated object and its attributes, is getting kind of involved. I was wondering if there is an easier way to do this then my way:
class Customer < ActiveRecord::Base
def hash
%{#{ name }#{ code }}.hash # There is a lot more here of course
end
def eql?(other)
hash == other.hash
end
def update_with(other)
name = other.name
code = other.code
etc ....
end
end
Ok it doesn't look like there is a standard solution so here is something I came up if anybody else is looking for it.
You can rename methods anyway you like, just put this in you lib folder in some .rb file. ( don't forget to mention it in environment.rb like so require 'custom_comparisons'
/lib/custom_comparisons.rb
module ActiveRecord
class Base
def comparison_hash
h = ""
self.attributes.each_pair do |key, value|
unless ["id", "updated_at", "created_at"].include?(key)
h << "#{value}"
end
end
h.hash
end
def eql_to?(other)
comparison_hash == other.comparison_hash
end
def differences_from?(other)
h = {}
self.attributes.each_pair do |key, value|
unless self.method_missing(key) == other.method_missing(key)
h[key.to_sym] = [self.method_missing(key), other.method_missing(key)]
end
end
h
end
end
end
This can be cleaned up a bit and I need to add association drill down but the solution is there.
This does the comparison and the shows the differences between objects. Now I can update attributes that need to be updated. Will add update method and drill down tomorrow.
My user model has three relations for the same message model, and is using raw SQL :/ Is there a better more rails way to achieve the same result?
Could the foreign key be changed dynamically? e.g User.messages.sent (foreign key = author_id) and User.messages.received (foreign key = recipient ) I have been trying to move some of the logic into scopes in the message model, but the user.id is not available from the message model...
Any thoughts?
Table layout:
create_table "messages", :force => true do |t|
t.string "subject"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "author_id"
t.integer "recipient_id"
t.boolean "author_deleted", :default => false
t.boolean "recipient_deleted", :default => false
end
This is my relations for my user model:
has_many :messages_received, :foreign_key => "recipient_id", :class_name => "Message", :conditions => ['recipient_deleted = ?', false]
has_many :messages_sent, :foreign_key => "author_id", :class_name => "Message", :conditions => ['author_deleted = ?', false]
has_many :messages_deleted, :class_name => "Message", :finder_sql => 'SELECT * FROM Messages WHERE
author_id = #{self.id} AND author_deleted = true OR
recipient_id = #{self.id} AND recipient_deleted = true'
Best regards.
Asbjørn Morell
Yes, use a named_scope for sorting between deleted and not deleted messages.
class User < ActiveRecord::Base
has_many :messages_received, :foreign_key => 'recipient_id'
has_many :messages_sent, :foreign_key => 'author_id'
end
class Messages < ActiveRecord::Base
named_scope :deleted, :conditions => 'author_deleted = TRUE OR recipient_deleted = TRUE'
named_scope :not_deleted, :conditions => 'author_deleted = FALSE OR recipient_deleted = FALSE'
end
# Example user
user = User.first
user.messages_received.deleted
user.messages_received.not_deleted
user.messages_sent.deleted
user.messages_sent.not_deleted
Alternatively, you could go one step further and simplfy the association by using the user_id as the foreign key and specifying the message type.
create_table "messages", :force => true do |t|
t.string "subject"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.string "message_type"
t.integer "user_id"
t.boolean "deleted", :default => false
end
class User < ActiveRecord::Base
has_many :messages
end
class Messages < ActiveRecord::Base
MESSAGE_TYPES = %w[Recipient Author]
belongs_to :user
named_scope :recipient, :conditions => {:message_type => 'Recipient'}
named_scope :author, :conditions => {:message_type => 'Author'}
named_scope :deleted, :conditions => {:deleted => true}
named_scope :not_deleted, :conditions => {:deleted => false}
# Convenience class methods
def self.sent
author.not_deleted
end
def self.received
recipient.not_deleted
end
end
# Example usage
user = User.first
user.messages.sent
user.messages.received
user.messages.deleted
This approach is advantagoues because:
One less column.
Extendable. Adding an additional message type in the future is trivial (Eg: Drafts).