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
Related
I have two models, Job and Survey. I am using the PaperTrail gem to track changes that occur on the models, and I want to save the job_id onto the version every time it’s created.
# app/models/job.rb
class Job < ActiveRecord::Base
has_paper_trail :ignore => [:id, :created_at, :updated_at],
:meta => { :resource_id => self.id }
has_one :survey
end
# app/models/survey.rb
class Survey < ActiveRecord::Base
has_paper_trail :ignore => [:id, :created_at, :updated_at],
:meta => { :resource_id => self.job_id }
belongs_to :job
end
# app/db/schema.db
# versions
create_table "versions", force: :cascade do |t|
t.string "item_type", null: false
t.integer "item_id", null: false
t.string "event", null: false
t.string "whodunnit"
t.text "object"
t.datetime "created_at"
t.text "object_changes"
t.integer "resource_id"
end
# surveys
create_table "surveys", force: :cascade do |t|
t.string "survey"
t.integer "job_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
When I run this code and try to save a new record, I get the following error:
undefined method `job_id' for #<Class:0x007fd53d70c0a0>
How do I correctly fetch the foreign job_id key from inside my Survey model?
Solved by using :job_id instead of self.job_id.
In my database I am trying to get a one to many relationship between outlets and articles.
I am getting the following error when that relationship is used:
undefined method `outlet_id' for #<Article:0x007fc353887e58>
Here are the models:
class Article < ActiveRecord::Base
belongs_to :analyst
belongs_to :outlet
has_and_belongs_to_many :loe
attr_accessible :article_body, :author, :distribution, :loe, :most_important, :pubdate, :publication, :state, :submitted, :summary, :title, :url, :analyst_id, :loe_ids, :outlet_id
end
class Outlet < ActiveRecord::Base
has_many :articles, foreign_key: :title
attr_accessible :distribution, :name, :state, :article_ids
end
Here are the schema:
create_table "articles_loes", :id => false, :force => true do |t|
t.integer "article_id"
t.integer "loe_id"
end
create_table "loes", :force => true do |t|
t.string "name"
t.string "customer"
t.integer "article_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "loes", ["article_id"], :name => "index_loes_on_article_id"
create_table "outlets", :force => true do |t|
t.string "name"
t.integer "articles_id"
t.integer "distribution"
t.string "state"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "outlets", ["articles_id"], :name => "index_outlets_on_articles_id"
And here is the chunk of the view that calls on :outlet :
<div class="span4">
<%= f.association :loe %>
<%= f.association :outlet %>
</div>
If anyone has any ideas I'd really appreciate them. I think I might need an index of Outlets in Article? I'm not really sure how to implement that if that is the case. Thanks in advance.
Right now there is no way for your Outlet model to associate with the articles that it has. Once you say belongs_to, you need to have an outlet_id column. So you need to add an outlet_id (integer) column to your Article model and populate it with the id of the outlet they belong to. If an Article can belong to many outlets in that case you need to create a many-to-many relationship through a joint table.
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.
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.
class Product < ActiveRecord::Base
has_many :models, :dependent => :destroy, :order => 'display, title'
class Model < ActiveRecord::Base
belongs_to :product
class GsCollector < ActiveRecord::Base
belongs_to :model
Why can't I do the following in my form for GsCollector?:
<p>
Model:<br />
<%= collection_select :gs_collector, :model_id, Product.where("title = 'Some Title'").models.all, :id, :title %>
</p>
I get the error:
undefined method `models' for #<ActiveRecord::Relation:0x007fef0ac09350>
Shouldn't the models method be provided by the relation? In the console, this works:
p = Product.find(4).models
But this doesn't:
p = Product.where("title = 'some title'").models
Not sure what the difference is....
Here's my schema:
create_table "gs_collectors", :force => true do |t|
t.integer "project_id"
t.integer "model_id"
t.integer "quantity", :default => 1
t.string "housing", :default => "Base Unit"
t.string "hopper"
t.string "controller"
t.boolean "overbags", :default => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "models", :force => true do |t|
t.string "title"
t.integer "product_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "display"
end
create_table "products", :force => true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
end
You are returning an array of objects, collectively called a ActiveRecord::Relation. This is due to your where search term. Maybe you want something like the following:
p = Product.find_by_title('some title').models
where returns a list of Products
find returns a single Product
You need to define the relationship between Model and GsCollector both ways. You forgot the part in the Model:
class Model < ActiveRecord::Base
belongs_to :product
has_many :gs_collectors
end
class GsCollector < ActiveRecord::Base
belongs_to :model
end
And the real problem is that you can .models only on a single record. Product.where returns several ones - so use Product.find_by_title("title").models