Creating Associations in Rails using has_many and belongs_to - ruby-on-rails

I know there are a lot of topics on this already but I couldn't find any that were what I'm trying to do. I'm just learning Rails and although I know this is probably a pretty simple fix, I'm stumped.
I'm creating a "Timeline" site. I have user accounts set up, and the user can create timelines. But, what I need to do is associate multiple timeline "events" (items to go in the timeline, the model for these is called Event) with each timeline (the model for which is called Timeline_Object). More plainly - a user has multiple timelines, and a timeline has multiple events.
The problem is that I can't get events set up with the timeline correctly. I think the association is set up correctly between users and timelines, but I'm not completely sure how to figure out what's wrong. Here are my models:
class User < ActiveRecord::Base
has_many :timeline_objects
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation,
:remember_me, :user_name
end
class TimelineObject < ActiveRecord::Base
belongs_to :user
attr_accessible :title, :user_id
has_many :events
end
class Event < ActiveRecord::Base
belongs_to :timeline_object
attr_accessible :date, :description, :time, :title, :image,
:image_width, :image_height, :timeline_objects
has_attached_file :image, :styles => { :large => "500x500>", :medium => "400x400#", :thumb => "100x100>" }
after_post_process :save_image_dimensions
validates :title, presence: true
validates :image, presence: true
validates :time, presence: true
validates :date, presence: true
def save_image_dimensions
geo = Paperclip::Geometry.from_file(image.queued_for_write[:original])
self.image_width = geo.width
self.image_height = geo.height
end
end
After running some migrations to set up the keys in the database, this is what my schema looks like:
ActiveRecord::Schema.define(:version => 20130402144923) do
create_table "events", :force => true do |t|
t.string "title"
t.string "description"
t.string "date"
t.string "time"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "image_height"
t.integer "image_width"
t.integer "timeline_objects"
end
add_index "events", ["timeline_objects"], :name => "index_events_on_timeline_objects"
create_table "timeline_objects", :force => true do |t|
t.string "title"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "user_id"
end
add_index "timeline_objects", ["user_id"], :name => "index_timeline_objects_on_user_id"
create_table "users", :force => true do |t|
t.string "user_name"
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
end
When I go to show the timeline (at which point all the events should be displayed), I try to loop through them with
<% #timeline_object.events.each do |event| %>
That line of code produces this error:
SQLite3::SQLException: no such column: events.timeline_object_id: SELECT "events".* FROM "events" WHERE "events"."timeline_object_id" = 4
So I realize that means I'm missing something in my database, but I'm not sure what I should change/add to make it all work.
Let me know if you need any additional info/code. Thanks in advance.

In your Events schema, you have:
t.integer "timeline_objects"
but, it should be:
t.integer "timeline_object_id"
Run a new migration to fix it:
rename_column :events, :timeline_objects, :timeline_object_id
Since each event belongs to a TimelineObject, then it needs a column that identifies the id of the object that it's associated to.

Related

Rails uniqueness validation based on relation

I have two models...
create_table "registrations", :force => true do |t|
t.integer "orientation_id"
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "student_id"
...
end
create_table "orientations", :force => true do |t|
t.date "class_date"
t.text "class_time"
t.integer "seats"
t.boolean "active", :default => true
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
I want to create a validation in my registration model that says the student_id must be unique in each Orientation.
If i understood your question correctly,you want the scope option of the validates_uniqueness_of.If so,this should work
In your Registration model,
Class Registration < ActiveRecord::Base
......
validates_uniqueness_of :student_id, scope: :orientation_id
end
And also,you should be generating a migration to add this
add_index :registration, [ :student_id, :orientation_id ], :unique => true
More Info here

join two tables to get data rails 4

class Guardian < ActiveRecord::Base
has_many :patients
has_one :user, as: :profile
accepts_nested_attributes_for :user
end
class User < ActiveRecord::Base
belongs_to :profile, :polymorphic => true
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
User migration
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
t.string :username, :null => false
t.string :address
t.integer :age
t.string :gender
t.string :name
t.integer :profile_id
t.string :profile_type
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0, :null => false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
end
end
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
t.string :username, :null => false
t.string :address
t.integer :age
t.string :gender
t.string :name
t.integer :profile_id
t.string :profile_type
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0, :null => false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
end
end
Guardian migration
class CreateGuardians < ActiveRecord::Migration
def change
create_table :guardians do |t|
t.string :family_name
t.timestamps
end
end
end
I want to get data from user table and guardian table in a single variable
guardian has one user and user belongs_to guardian as profile(polymorphic). i want to get data from user table and from guardian table where guardian_id=users.profile_id
Try
Guardian.select("*").joins(:user)
Edit:
if you have columns with the same name from the join you can do
Guardian.select("guardians.family_name, guardians.id as g_id, users.id as u_id,
users.name, users.email, users.username, users.address, users.age,
users.gender").joins(:user).where(:users => {:u_id => #user_session.id})
For some reason above answer didn't work for me, so I tried direct sql query
sqlQuery = "select tableA.column1, tableB.column2 from tableA inner join tableB on tableA.some_id = tableB.id"
ActiveRecord::Base.connection.execute(sqlQuery)

One to Many Relationship: List of many not showing up

I have a simple one to many relationship mapping users to posts. Here is the relevant part of the schema:
create_table "users", :force => true do |t|
t.string "username"
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "password"
t.string "status", :default => "User"
t.string "img_url"
t.text "bio"
t.integer "num_posts", :default => 0
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "posts", :force => true do |t|
t.string "subject"
t.text "body"
t.integer "user_id"
t.integer "section_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
And here are the models:
class User < ActiveRecord::Base
attr_accessible :bio, :email, :first_name, :img_url, :last_name, :num_posts, :password, :status, :username
has_many :posts
has_many :comments
end
class Post < ActiveRecord::Base
attr_accessible :body, :section_id, :subject, :tag_ids, :user_id
belongs_to :user
belongs_to :section
has_and_belongs_to_many :tags
has_many :comments
end
I go into the rails console and create a new user doing User.create(attributes) and a new post doing Post.create(some attributes), assinging them to p1 and u1, respectively, then I do p1.user = u1.
Now when I do p1.user, I get a u1 object. Moreover, I can see that the user_id key is set to the key of u1 in the DB. However, when I do u1.posts, I get an empty list. How can I get a list of all of the posts that belong to a given user?
Ideally, when creating posts, you can create like this:
user.posts.create!({attributes})
Here in your case it could be the problem with association caching. Try
u1.reload.posts

Restrict attr_accessible to types of user with Ruby on Rails

I am creating a forum software. I want admins and mods to be able to close certain topics.
Codes are sanitized to show only relevant info.
Models
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :bio
has_many :topics, dependent: :destroy
end
class Topic < ActiveRecord::Base
belongs_to :user
attr_accessible :name, :last_post_id, :content
end
Schema for user: admin and mod columns determine admins and mods.
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "password_digest"
t.string "remember_token"
t.boolean "admin", :default => false
t.text "bio"
t.boolean "mod", :default => false
end
Schema for topic: closed column determines topic's closed status.
create_table "topics", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "forum_id"
t.string "name"
t.integer "last_post_id"
t.integer "views"
t.integer "user_id"
t.boolean "closed", :default => false
t.text "content"
end
I am reluctant to user attr_accessible :closed for TOPIC model because it will be vulnerable to malicious PUT request (correct me if I am wrong).
Is there some way for Rails app to be able to access and modify value of closed column of TOPIC without using attr_accessible, so that only mods and admins can edit them?
I searched on google and found this ascii cast.
Basically, you are looking for dynamic attr_accessible.
If you currently have
class Article < ActiveRecord::Base  
  attr_accessible :name, :content, :closed  
end  
You ca use dynamic attr_accessible like this :
class Article < ActiveRecord::Base  
  attr_accessible :name, :content  
 private  
def mass_assignment_authorizer  
    super + [:closed]  
  end  
end  
I hope I is what you are looking for.
Be sure to check the link I gave you for complete reference.

Active Admin NoMethodError Error

Im setting up active admin on my rails app. I ran the generator to create the user resource but when i click on the users link on the admin dashboard i get:
NoMethodError in Admin/users#index
Showing /Users/nelsonkeating/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/gems/1.9.1/gems/activeadmin-0.4.4/app/views/active_admin/resource/index.html.arb where line #1 raised:
undefined method `city_id_contains' for #<MetaSearch::Searches::User:0x007fde92d69840>
Extracted source (around line #1):
1: render renderer_for(:index)
I have no clue what is generating this or where the error is coming from.. Any ideas? Thanks! (please let me know if you need to see any other files)
Models:
user.rb
class User < ActiveRecord::Base
rolify
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :province_id, :city_id
belongs_to :province
belongs_to :city
province.rb
class Province < ActiveRecord::Base
has_many :cities
has_many :users
end
city.rb
class City < ActiveRecord::Base
belongs_to :province
has_many :users
end
schema.rb
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "name"
t.date "date_of_birth"
t.string "address"
t.string "gender"
t.integer "zipcode"
t.string "city"
t.string "status"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "province_id"
t.integer "city_id"
end
create_table "provinces", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "cities", :force => true do |t|
t.string "name"
t.integer "province_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
This question helped me solve my problem. I had to read the comments to figure out how to solve it so I am providing the answer here:
If you have a model that contains a belongs_to relationship, Active Admin will not like it if you have a column name that matches your belongs to foreign key id column name.
For instance in this case your foreign key is 'city_id' but you also have a column named 'city'. Active Admin doesn't like this. And likewise it really doesn't make sense to have that column to begin with. Since you will access the city through the relationship.
To fix this you should create a migration that removes the city column.
class RemoveCityFromUser < ActiveRecord::Migration
def up
remove_column :users, :city
end
end

Resources