简体   繁体   中英

Join tables - Associations in Rails 3

For example I have 2 tables: topics and comments.

topic has_many comments. comment belongs_to topic.

Comments table have column sender_id where I save user's id, who create this comment.

Task: Select ids of topics, which is not commented by this user (I know user_id). (I want to do it with one query).

Earlier I do it so. ( two queries ) ( My database - PostgreSQL)

incorrect_topics = Comment.select(:topic_id).where(:sender_id => user_id).map { |elem| elem.topic_id }
ids = select(:id).where(["id NOT IN (?)", incorrect_topics]).map { |elem| elem.id }

It works fine, but I suppose that if app become bigger it will be serious problem.

Thanks.

If all you need are the IDs then you could bypass all the ActiveRecord stuff and do it by hand:

ids = connection.select_rows(%Q{
    select id
    from topics
    where id not in (
        select topic_id
        from comments
        where sender_id = #{user_id.to_i}
    )
}).map { |r| r.first.to_i }

If you're certain the user_id is already an integer then you don't need the .to_i . You could also use #{connection.quote(user_id)} . You could also use the same SQL with select_values if you wanted to avoid unwrapping he rows by hand with a map .

If you wanted the Topic instances then find_by_sql would be an option:

topics = find_by_sql(%q{
    select *
    from topics
    where id not in (
        select topic_id
        from comments
        where sender_id = :user_id
    )
}, :user_id => user_id)

Some things are clearer when you use straight SQL than when you try to wrap it up in ActiveRecord stuff.

Maybe something like this could work:

incorrect_topics = Comment.where('sender_id <> ?', user_id).topics

Let me know if helps you anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM