Rails 3 Querying: Find all Posts with the same Topic - ruby

I am trying to create a query that finds all the Posts that belong to the same Topic id. I believe I'm on the right track, but all #posts returns is every post in the database.
Topics controller:
def show
#topic = Topic.find(params[:id])
#title = #topic.name
#posts = Post.where('topic' == #topic).order("updated_at").page(params[:page]).per(10) #not working. still just fetches all posts
respond_with(#posts)
end
Topic model:
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
attr_accessible :name
end
Post model:
class Post < ActiveRecord::Base
belongs_to :topic, :touch => true
accepts_nested_attributes_for :topic
attr_accessible :name, :title, :content, :topic, :topic_attributes
end

I would recommend you to use the association in the model to get all the posts. you could do it like this:
def show
#topic = Topic.find(params[:id])
#title = #topic.name
#posts = #topic.posts.order("updated_at").page(params[:page]).per(10)
respond_with(#posts)
end

You can use the ActiveRecord association to do this:
def show
#topic = Topic.find(params[:id])
#title = #topic.name
#posts = #topic.posts
respond_with(#posts)
end

And if you are going to use 'where' you should use it like this:
Post.where('topic_id' => #topic.id)
This is because topic refers to the activerecord association. But how its stored in the db level is different.
whats inside where is 'almost' sql.

Related

Calling a Associated Controller Method Not Working

I have 3 models of User, Role and UserRole with their respective controllers as UsersController, RolesController and UserRolesController.
I have a method in the UserRoles controller which I would want to access through the Users controller but I keep having errors as explained below.
I have tried various means of even moving the method def self.add_roles_to_user(user, role) from the UsersRoles controller into the UserRole model and call it but I keep having the same error.
I have gone through lots of similar questions and various blogs, including those on this platform such as Calling a method from controller, and others but to no good results.
class UserRole < ApplicationRecord
# many-to-many association using join table with roles and user
belongs_to :user, inverse_of: :user_roles
belongs_to :role, optional: true, inverse_of: :user_roles
end
class User < ApplicationRecord
has_many :user_roles, inverse_of: :user
has_many :roles, through: :user_roles
end
class Role < ApplicationRecord
# table associations between role and user
has_many :user_roles, inverse_of: :role
has_many :users, through: :user_roles
end
class UserRolesController < ApplicationController
def self.add_roles_to_user(user, role)
if ! user.nil?
if role.length > 0
role.each do |sel_role|
#u_role = UserRole.new
#u_role.user_id = user_id
#u_role.role_id = sel_role.role_id
#u_role.save
end
end
end
end
end
class Users::RegistrationsController < Devise::RegistrationsController
def create_user
respond_to do |format|
if #user.save
# add roles
UserRoles.add_user_roles(params[:user], params[:role])
end
end
end
end
I am calling the add_uer_to_role method in the User controller when I am adding or creating a new user.
What I have noticed is that I keep getting different errors based on how I call the method.
For example, I expect to have no errors when I call the method like; UserRoles.add_roles_to_user(params[:user], params[:role]) but it gives the error NameError (uninitialized constant Users::RegistrationsController::UserRoles):
Hoping a good samaritan will come to my aid as soon as possible. Thanks in advance
If it is a common function, you can define it in application controller and call it. Else you can define in helper.
Please verify Calling a method from another controller
You can use that function as a module and use it:
# lib/common_stuff.rb
module CommonStuff
def common_thing
# code
end
end
# app/controllers/my_controller.rb
require 'common_stuff'
class MyController < ApplicationController
include CommonStuff
# has access to common_thing
end

Look for help on Ruby on Rails

I am new with Ruby on Rails. I just build web application on the existing database. I use rails to generate 2 scaffolds for restaurant and location tables. After that I set relationship for these two tables:
class Restaurant < ActiveRecord::Base
attr_accessible :created, :cuisine_fk, :dish_keywords, :dish_names, :factual_id, :first_name, :last_name, :name, :status
has_many :locations
end
class Location < ActiveRecord::Base
attr_accessible :address1, :address2, :city, :created, :latitude, :longitude, :phone, :restaurant_fk, :state, :status, :url, :zip
belongs_to :restaurant
end
I didn't use "rake db:migrate" after I set up this relationship for these tables, because I was afraid that this action would make changes the existing tables.
When I run this command line
<%= restaurant.location.address1%>
it shows error:
undefined method `location'
" NoMethodError in Restaurants#index
Showing C:/Sites/Dishclips/app/views/restaurants/index.html.erb where line #52 raised:
undefined method `location' for #<Restaurant:0x5853bb8> "
After that I tried to set foreign key for the file:
class Location < ActiveRecord::Base
attr_accessible :address1, :address2, :city, :created, :latitude, :longitude, :phone, :restaurant_fk, :state, :status, :url, :zip
belongs_to :restaurant, :class_name => "Restaurant", :foreign_key => 'restaurant_fk'
end
but it still doen't work.
Is there any way that we can set foreign keys in stead of using "rails db:migrate" after we set up the relationships for tables ? I appreciate your help a lot.
The problem is that you are using location wrongly.
Since the restaurant has_many locations you can't use it the way you mentioned. Because you have an array of locations, actually is a ActiveRecord relationship, so in order to access one of the items assciated you'll have to execute the query and get one of the elements. Here is an example of how to get the first element.
restaurant.locations.first.address1
If the restaurant have only one location, than you should change your model to
class Restaurant < ActiveRecord::Base
attr_accessible :created, :cuisine_fk, :dish_keywords, :dish_names, :factual_id, :first_name, :last_name, :name, :status
has_one :locations
end
and access the property as you are doing:
restaurant.location.address1
Also I'm assuming that your database have the columns you specified, otherwise you'll have to run the migrations.
Regards!
Rails associations are covered very well here in the Rails Guides.
I'll walk you through a basic setup here.
$ rails generate model Restaurant name owner ...
$ rails generate model Location restaurant_id:integer city ...
You then need to migrate your database with rake db:migrate for the database table changes to become effective.
The restaurant_id allows us to set the associations in our models as follows
class Restaurant < ActiveRecord::Base
has_many :locations, dependent: :destroy
attr_accessible :name, :owner
end
class Location < ActiveRecord::Base
belongs_to :restaurant
attr_accessible :city # no restaurant_id here
end
Now you can access your restaurants location as follows.
r = Restaurant.create!(name: '...')
l = Location.create!(city: '...')
# Add association
r.locations << l
r.locations will now return an Array with l in it
l.restaurant will return r
Try to play a little with the different styles of associations, for example by creating new Rails apps quickly and just trying some kind of associations, also some that require a join model.
Now I try this way, then it works. Thank you very much.
<td>
<% restaurant.locations.search(params[:restaurant_fk]).each do |location| %>
<!--address = <%= location.address1 %> + " " + <%= location.address2 %>-->
<%= location.address1 %>
<%= location.address2 %> ,
<%= location.city %> ,
<%= location.state %> ,
<%= location.zip %>
<% end %>
</td>

"Retweets" with Datamapper

I want to impliment something which is similar to Twitter Repost System, therefore I will use this as an example. So let's say I have a Tweet Model and I want to allow other user to repost a certian tweet of another user, how do I impliment something like this?
I thought I would be a cool idea to put the retweet class into the tweet to be able to acess the repost too when I use Tweet.all to recive all tweets stored in the database, but somehow I didn't worked as expected...
The following Code is just an example which should show how to impliment this even if it is not working...
Any ideas how I could build a working repost model which also allows me to access both tweets and retweet by using Tweet.all?
class Tweet
class Retweet
include DataMapper::Resource
belongs_to :user, key => true
belongs_to :tweet, key => true
end
include DataMapper::Resource
property :text, String
property :timestamp, String
belongs_to :user
end
Important: I should be carrierwave compatible.
class Tweet
include DataMapper::Resource
property :id, Serial
has n, :retweets, 'Tweet', :child_key => :parent_id
belongs_to :parent, 'Tweet', :required => false
belongs_to :user
def is_retweet?
self.parent_id ? true : false
end
end
original = Tweet.create :user => user1
retweet = Tweet.create :parent => original, :user => user2
retweet.is_retweet? # => true

Rails multiple belongs_to assignment

Given
User:
class User < ActiveRecord::Base
has_many :discussions
has_many :posts
end
Discussions:
class Discussion < ActiveRecord::Base
belongs_to :user
has_many :posts
end
Posts:
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :discussion
end
I am currently initializing Posts in the controller via
#post = current_user.posts.build(params[:post])
My question is, how do I set/save/edit the #post model such that the relationship between the post and the discussion is also set?
Save and edit discussions along with post
Existing Discussion
To associate the post you're building with an existing discussion, just merge the id into the post params
#post = current_user.posts.build(
params[:post].merge(
:discussion_id => existing_discussion.id
)
You will have to have a hidden input for discussion id in the form for #post so the association gets saved.
New Discussion
If you want to build a new discussion along with every post and manage its attributes via the form, use accepts_nested_attributes
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :discussion
accepts_nested_attributes_for :discussion
end
You then have to build the discussion in the controller with build_discussion after you built the post
#post.build_discussion
And in your form, you can include nested fields for discussions
form_for #post do |f|
f.fields_for :discussion do |df|
...etc
This will create a discussion along with the post. For more on nested attributes, watch this excellent railscast
Better Relations
Furthermore, you can use the :through option of the has_many association for a more consistent relational setup:
class User < ActiveRecord::Base
has_many :posts
has_many :discussions, :through => :posts, :source => :discussion
end
class Discussion < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :discussion
end
Like this, the relation of the user to the discussion is maintained only in the Post model, and not in two places.

Validation error in test but error array is empty

I have this code for creating a topic and post in a forum application in Rails 3.1:
def create
#topic = Topic.new(:name => params[:topic][:name], :last_post_at => Time.now)
#topic.forum_id = params[:topic][:forum_id]
#topic.user = current_user
if #topic.save
#post = Post.new(:content => params[:post][:content])
#post.topic = #topic
#post.user = current_user
#post.save!
...
When posting to the create method via the corresponding form, the topic and the post are created and both save calls are successful.
When I call the create method via a functional test, the topic is saved but the post has validation errors.
ActiveRecord::RecordInvalid: Validation failed:
app/controllers/topics_controller.rb:23:in `create'
test/functional/topics_controller_test.rb:26:in `block in <class:TopicsControllerTest>'
The test looks like this:
test "should create topic" do
post :create, :topic => {:name => "New topic", :forum_id => forums(:one).id}, :post => {:content => "Post content"}
end
(current_user is logged in via a setup method.)
When I display the errors of the post object via the debugger or with #post.errors.full_messages, the error array is empty.
The Post model looks like this:
class Post < ActiveRecord::Base
attr_accessible :content
belongs_to :topic
belongs_to :user
end
And the Topic model:
class Topic < ActiveRecord::Base
belongs_to :user
belongs_to :last_poster, class_name: 'User'
attr_accessible :name, :last_poster_id, :last_post_at
belongs_to :forum
has_many :posts, :dependent => :destroy
end
How can I find out what is causing the validation error?
The problem was that I used mocha's Post.any_instance.stubs(:valid?).returns(false) in a test that was executed before my failing test.
Apparently, you have to restore the original behavior before proceeding with other tests by calling Post.any_instance.unstub(:valid?).

Resources