rails: best way to store comments in mysql - ruby-on-rails

Okay i have two models: posts and comments.
as you can think comments has column :post_id.
My models
Comments
belongs_to :post
Post
has_many :comments
So, this is pretty simple association but i have some problems with ordering comments.
at first time, when i create my comments migration file i just add column :position.
This column indicate comment position in the post.
But now i think what where is more good way to do this.
so i can't make my choise:
1) uses t.column :datatime :created_at, :default => Time.now()
2) or use timestamps? this is undiscovered for me, please tell me about your exp.

yar is right. No need to have a position column, unless you'll want to reorder your comments, which I doubt you will :) Just do
has_many :comments, :order => "created_at DESC"
and every time you use #post.comments they will be sorted by date.

In Rails, all models automatically get a created_at field. You can just order by that.

Related

what data type to use for user created object in a ruby create file

I built a simple blog following a tutorial. But then I wanted to try something a little bigger. So i wanted to make a blog with comments and users. Which means now my post need a user and an array of comments. My comments need to belong to a post, and my user has many posts and comments. So the question is in my create files how do i handle that. I was just using string, text and integer. But what are they for arrays and user created models? Here is a link on gist to see the code Also if there is anything that I am not doing that looks like a potential pit fall please let me know. Secondly, previously when i added a new variable to a model I found if i wanted to update the schema I had to rake db:rollback and then migrate again. Because just trying to migrate over the top did not update my schema. Is there a better way to do that?
thanks.
Not sure what tutorial you are following, but the best blog app tutorial is found in the official docs.
After reading through that you'll see that you are missing the main concept of model objects.
You will have three models: User, Post, Comment.
Models would look like this:
User
has_many :posts
has_many :comments
Post
belongs_to :user
has_many :comments
Comment
belongs_to :user
belongs_to :post
In your migrations you will simple use an integer to define the belongs_to relationship.
In the Post migration: (this will vary depending on how you do your migrations, but concept is the same)
t.integer :user_id
For Comment:
t.integer :user_id
t.integer :post_id
Read through the guides and you will be fine.
Post should belong_to :user rather than has_one :user.
You'll want to do a bit of research on database schema design, but basically you need to add foreign keys to your tables and setup relationships between them.
For example, your comments table will need a user_id integer. This will allow a particular comment to "point at" a user, so your application knows who wrote the comment.
Then in your User model, you should add the following:
has_many :comments
And in your Comment model:
belongs_to :user
The same basic idea can be applied to posts.

Counting number of associations across several Rails objects

class Article
has_many :comments
end
class Comment
belongs_to :article
end
I'd like to be able to determine how many total comments exist for certain articles. For example: Article #20, #21 and #22 have a total of X comments between them.
Any pointers would be great!
I suggest this:
Comment.where(:article_id => [20, 21, 22]).count
Doing the counting etc. in the database and all in one query (which ActiveRecord will, in this case) is about as efficient as possible.
You could add a counter_cache to your articles table
class Article
has_many :comments, :counter_cache => true
end
and add a comments_count column to your articles table.
(http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html) and then sum it as so.
Article.where(:id => [20,21,22]).sum(:comments_count)
You can easily do this without a counter cache if you prefer.
Article.where(:id => [20,21,22]).joins(:comments).count

Hacker News rails clone: advice on modeling relationship between links, comments and votes

I'm loving Rails but we just started dating.
A user can vote on both links and comments. In addition to primary key and timestamp, I currently have the following attributes defined for these models:
Link url, headline, submitter_id, score
Comment content, commenter_id, score, link_id, parent_comment_id
Vote id, voter_id, link_id, direction
I just added the Comment Model and thinking through how to integrate it with votes. Some options:
Collapse links and comments into a single "Item" model, and map votes to the generic item_id
Have two vote tables, one for comments, one for links
Add comment_id column to existing Vote table
Not sure what's best. #1 and #3 introduce dual-purpose tables, i.e. there are certain columns in a table that are only relevant to subsets of rows within that table. #2 avoids this problem, but seems redundant and silly.
Is the tradeoff inevitable or am I not seeing the golden path? What would you recommend? And if you happen to know of a rails repository on github that handles a similar situation, I'd really appreciate a link!
I think what you are looking for is a polymorphic association. In your case would be as simple as :
class Vote < ActiveRecord::Base
belongs_to :votable, :polymorphic => true
end
class Link < ActiveRecord::Base
has_many :votes, :as => :votable
end
class Comment < ActiveRecord::Base
has_many :votes, :as => :votable
#...
end
Your votes table should look like:
id : integer
votable_id : integer
votable_type : string # Comment || Link
Here you have a Railscast about it: Polymorphic Associations Railscast

Rails 3 joins with non-standard key fields

I have googled myself almost to death over this and the closest I came to anything similar is this stack overflow question (which attempts to ask several questions at once). I have only one. OK, two - but providing an answer to the first will get your answer accepted as long as it adheres to the requirements below.
I am using Rails 3 and Ruby 1.8.7 with a legacy database. The only thing that is up for debate is the Rails version. I am stuck with Ruby 1.8.7 and the database structure.
Here are the significant portions of the models involved:
class List < ActiveRecord::Base
set_primary_key "ListID"
has_many :listitem, :foreign_key => "ListID", :dependent => :destroy
has_many :extra_field, :foreign_key => "ListID", :dependent => :destroy
end
class Listitem < ActiveRecord::Base
set_table_name "ListItems"
set_primary_key "ListItemID"
belongs_to :list
has_many :list_item_extra_field, :foreign_key => 'ListItemID', :dependent => :destroy
end
This is what I get in rails console:
irb(main):001:0> List.joins(:listitem).to_sql
=> "SELECT [lists].* FROM [lists] INNER JOIN [ListItems] ON [ListItems].[ListID] IS NULL"
When I am expecting a sql statement more like:
SELECT [lists].* FROM [lists] INNER JOIN [ListItems] ON [ListItems].[ListID] = [Lists].[ListID]
Getting me to the query above will get a correct answer. Bonus points if you can tell me how to get to something equivalent to:
SELECT [lists].*, COUNT([ListItems].*) FROM [lists] INNER JOIN [ListItems] ON [ListItems].[ListID] = [Lists].[ListID]
Your first question: you probably messed with table migration. In migration file use
create_table :lists, {:id => false} do
....
end
and then add execute "ALTER TABLE lists ADD PRIMARY KEY (listid);"
And by the way, it's has_many :listitems (plural, not single).
Look here for detailed explanation: Using Rails, how can I set my primary key to not be an integer-typed column?
Second question: I would use combination of methods, not one method. YOu need to return name of list and then count name of list items in this list, right? After solving the first problem, simply use list.name and list.list_items.count
As usual, the answer is ridiculously simple with Rails...
My tables are named using mixed case. Adding the following line to my List model fixed it:
set_table_name "Lists"
The plurality (or lack thereof) of :listitem(s) appeared to have no effect before or after this change.

Eager-loading association count with Arel (Rails 3)

Simple task: given that an article has many comments, be able to display in a long list of articles how many comments each article has. I'm trying to work out how to preload this data with Arel.
The "Complex Aggregations" section of the README file seems to discuss that type of situation, but it doesn't exactly offer sample code, nor does it offer a way to do it in two queries instead of one joined query, which is worse for performance.
Given the following:
class Article
has_many :comments
end
class Comment
belongs_to :article
end
How can I preload for an article set how many comments each has?
Can't you use counter cache for this?
belongs_to :article, :counter_cache => true
You also need to have a migration that adds the column comments_count
You can do something nasty using SQL like:
default_scope :select => 'articles.*, (select count(comments.id) from comments where comments.article_id = articles.id) as count_comments'
and then you would have access to Article.first.count_comments.
Another (nicer) method to do it is to use the 'counter_cache' feature/option from belongs_to association.

Resources