0

I'm used to MySQL but trying to use Ruby on Rails right now. In MySQL, I would have two tables, with one containing a reference to another ("posts" referring to "topic"). A MySQL query doing what I want would be similar to "SELECT * FROM Posts WHERE posts.topic="topic" ("topic" here is a variable).

However, trying to work with the Ruby model stuff has me confused. The variables being passed between the controller and view are null because they are empty tables.

In my controller:

def topic @topic = Topic.where(params[:topic]) @posts = Post.where(topic: @topic.object_id) end 

I don't know how to select the posts which have the topic defined by the "topic" variable.

In the view:

<% @posts.each do |post| %> <p><%= post.title %></p> <% end %> 

The migration files:

class CreatePosts < ActiveRecord::Migration def change create_table :posts do |t| t.string :title t.string :text t.references :topic t.timestamps end end end class CreateTopics < ActiveRecord::Migration def change create_table :topics do |t| t.string :topic t.timestamps end end end 

3 Answers 3

1

Given that Post and Topic are related, according to your migrations at least, in the models you should be stating"

class Topic has_many :posts 

and

class Post belongs_to :topic 

Given that you then have an instance of Topic, @topic, you can retrieve all the related records with:

@posts = @topic.posts 
Sign up to request clarification or add additional context in comments.

Comments

0

I think those methods you put in your controller are fine where they are, but keep in mind that the Rails way is "fat models, skinny controllers." If you put that logic in the model as a method, it's much easier to read in the controller. Also, you should look into scopes, as they'll help you with queries like this down the line too.

In any case, you should stick the following in your Topic model:

scope :by_name, ->(name) { where(topic: name) } 

That's essentially the same as doing the following:

def self.by_name(name) where(topic: name) end 

On your posts model, you'd be able to do the following:

scope :by_topic, ->(topic) { where(topic_id: topic) } 

The other problem with what you've stuck in your controller is that when you use scopes, or a "where", it returns an array that contains all of the different records that match your query terms. So, when you call @topic = Topic.where(params[:topic]), you're getting back an array of objects. Therefore, when you do a @topic.id, you're trying to get back the id of an array instead of one object.

Based off of what I showed you before, it makes much more sense for you to do this:

def topic @topic = Topic.by_name(params[:topic]).first #this returns the first record @post = Post.by_topic(@topic.id) end 

That will return an array of posts that match the first topic name that you query for.

Comments

0

Alright, first a primer on how database design and how Rails (really, ActiveRecord) works. Basically, you should be connecting posts.topic_id = topic.id, not posts.topic = topic.topic.

Your migration is correct as is, create_table automatically includes an :id PRIMARY KEY column. That said you should know that these are all equivalent:

t.references :topic t.belongs_to :topic t.integer :topic_id 

In your view, instead of embedding topic.topic and passing that to the controller when the form is submitted, embed topic.id (the documentation for the select helper has a good example of this) and in your controller:

@topic = Topic.find params[:id] @posts = @topic.posts 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.