I have two controllers- a ProfilesController and a UsersController. I have a page full of blog posts, and I want each to have a link to the profile of the user who created them. I've been having a wee problem with this lately, and I want to start fresh, but don't know where to begin. How can I go about this?
Post controller:
def index
#shit = Static.all.order('id DESC')
if params[:search]
#posts = Post.search(params[:search]).order("created_at DESC").paginate(page: params[:page], per_page: 5)
else
#posts = Post.all.order('created_at DESC').paginate(page: params[:page], per_page: 5)
end
end
Profiles model:
class Profile < ApplicationRecord
belongs_to :user
end
Users model:
class User < ApplicationRecord
has_secure_password
validates :username, uniqueness: true
has_many :posts, foreign_key: :author
has_many :comments, foreign_key: :author
has_one :profile, foreign_key: :user
after_create :build_profile
def build_profile
Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly.
end
end
BTW not using Devise
Use joins
def index
#shit = Static.all.order('id DESC')
scope =
if params[:search]
Post.search(params[:search])
else
Post.all
end
#posts =
scope.
joins(:users).
joins(:profiles).
order("created_at DESC").
paginate(page: params[:page], per_page: 5)
end
In single #post object you should have relation to owner (user). In your view for each post use route for user_path but provide it with #post.user
Example in view
<% #posts.each do |post| %>
<%= link_to user_path(post.user) %>
//Rest of post content
<% end %>
Related
I have
message table
and
message_pictures
table(It belongs to the message table) and what I want to do is retrieve each messsge pictures (if there is any) from the
message_controller
.
How can I do it. I have surfed the web but found little scanty explanations on it.
This is the message class(model)
class Message < ApplicationRecord
belongs_to :user
has_many :message_pictures, dependent: :destroy
accepts_nested_attributes_for :message_pictures
end
This is the message_pictures class(model)
class MessagePicture < ApplicationRecord
belongs_to :message, optional: true
mount_uploader :message_pictures, PictureUploader
end
and this is the index method of the message_controller class
def index
#user = User.find(current_user.id)#414, 449, 494
#messages = #user.messages.paginate(page: params[:page])
##messages = #messages.message_pictures.paginate(page: params[:page])
end
You can see the line 4 of the index method to see the way I did mine but its not working
I believe what you need is has_many ... :through
app/models/user.rb
class User < ApplicationRecord
# ...
has_many :messages, dependent: :destroy
has_many :message_pictures, through: :messages
end
app/controllers/messages_controller.rb
class MessagesController < ApplicationController
# ...
def index
#user = User.find(current_user.id)
#messages = #user.messages.paginate(page: params[:page])
#message_pictures = #user.message_pictures
end
end
has_many ... :through simplifies the retrieving of "nested" children records via "SQL JOINS", of which normally you would have done it in a longer (more explicit way) like the following (which also works):
class MessagesController < ApplicationController
# ...
def index
#user = User.find(current_user.id)
#messages = #user.messages.paginate(page: params[:page])
#message_pictures = MessagePicture.joins(message: :user).where(
messages: { # <-- this needs to be the table name, and not the association name, and is why it is in plural form
users: { # <-- this needs to be the table name, and not the association name, and is why it is in plural form
id: #user.id
}
}
)
end
end
Update: Alternative Solution
Looking back at your question, I have a feeling you'd only want #message_pictures that corresponds to #messages and not to all#user.messages, because I noticed you have pagination for the messages. I'll do it like this instead:
app/controllers/messages_controller.rb
class MessagesController < ApplicationController
# ...
def index
#user = User.find(current_user.id)
# the `includes` here prevents N+1 SQL queries, because we are gonna loop
# through each `message_picture` in each `message` record (see index.html.erb below)
#messages = #user.messages.includes(:message_pictures).paginate(page: params[:page])
end
end
app/views/messages/index.html.erb (example)
<h1>Messages:</h1>
<% #messages.each do |message| %>
<section>
<h2>Message:</h2>
<p><%= message.content %></p>
<h3>Message Pictures:<h3>
<div>
<% message.message_pictures.each do |message_picture| %>
<% message_picture.message_pictures.each do |message_picture_attachment| %>
<%= image_tag message_picture_attachment.url.to_s %>
<% end %>
<br>
<% end %>
</div>
</section>
<% end %>
^ Above assumes MessagePicture is using carrierwave. P.S. It looks to me there's something wrong with how you defined your models, because your message has many message_pictures, while each of the message_picture also has many attached message_picture carrierwave attachments (assuming you used the "multiple-file" upload set up for carrierwave because you used mount_uploader :message_pictures, PictureUploader instead of mount_uploader :message_picture, PictureUploader. The model problem I think is because it's like this: message < message_pictures < message_pictures attachments, but (depending on your use-case), it should probably be just like message < message_pictures - message_picture attachment, or just simply message < message_pictures attachments
Im building a search field for my profile model, the search field takes in a list of skills separated by comas and find the profiles that have those skills. The code splits up the string by comas into multiple strings in an array. Now I am trying to find profiles that have all the skills in that array but I can't seem to wrap my head around it. I've tried playing around with PSQL code in where() but I can only seem to get it to work with 1 of the skills.
I am following the advanced search guide by ryan bates.
Profile.rb
class Profile < ApplicationRecord
belongs_to :user, dependent: :destroy
has_many :educations
has_many :experiences
has_many :skills
has_many :awards
has_many :publications
def owner? user
if self.user == user
return true
else
return false
end
end
end
business_search.rb
class BusinessSearch < ApplicationRecord
def profiles
#profiles ||= find_profiles
end
private
def find_profiles
profiles = Profile.all
if self.skills.present?
profiles = profiles.joins(:skills)
skills_array(self.skills).each do |skill|
profiles = profiles.where('skills.name_en = :q or skills.name_ar = :q', q: skill)
end
end
profiles
end
def skills_array(skills)
return skills.split(/,/)
end
end
business_search_controller.rb
class BusinessSearchesController < ApplicationController
def new
#search = BusinessSearch.new
end
def create
#search = BusinessSearch.create!(search_params)
redirect_to #search
end
def show
search = BusinessSearch.find(params[:id])
#profiles = search.profiles
end
private
def search_params
params.require(:business_search).permit(:first_name, :education_field, :skills)
end
end
Adavanced search view
<h1>Advanced Search</h1>
<%= form_for #search do |f| %>
<div class="field">
<%= f.label :skills %><br />
<%= f.text_field :skills %>
</div>
<div class="actions"><%= f.submit "Search" %></div>
<% end %>
Try this query:
def find_profiles
return Profile.all if skills.blank?
Profile.joins(:skills)
.where('skills.name_en IN (:skills) OR skills.name_ar IN (:skills)', skills: skills_array(skills))
.group('profiles.id')
.having('COUNT(skills.id) = ?', skills_array(skills).size)
end
Try this one:
def find_profiles
return Profile.all if skills.blank?
Profile.joins(:skills).where('skills.name_en IN (:skills) OR skills.name_ar IN (:skills)', skills: skills_array(skills))
end
I need to filter the posts that appear on my index page. I filtered them initially by using this condition in the view:
if current_user.courses.any? {|h| h[:name] == post.course.name}
But since I added will_paginate, I get blank pages because it paginates even the posts I don't want to show. How can I use a scope to filter out the posts in the controller?
These are my models:
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :course
has_many :comments
end
and
class Course < ActiveRecord::Base
belongs_to :user
has_many :posts
belongs_to :major
end
and my controller codes
def index
#posts = Post.all.order("created_at DESC").paginate(:page =>
params[:page], :per_page => 1)
end
If your filter contains more than one courses names :
def index
#posts = Post.joins(:course).where('courses.name in (?)',current_user.courses.map(&:name)).paginate(:page => params[:page], :per_page => 1)
end
I'm trying to paginate my posts under it's forum_thread_id.
When I paginate #forum_posts I'm getting all the posts and not the ones specific to the thread id that I'm in.
I'm using will_paginate for pagination.
It's probably any easy fix that I'm not seeing.
You have to filter the query with the ForumThread id, try something like this (modify the code accordingly)
def show
#forum_post = ForumPost.new
#forum_posts = ForumPost.where(forum_thread_id: #forum_thread.id).paginate(:page => params[:page], :per_page => 3)
end
Your problem is here:
def show
#forum_post = ForumPost.new
#forum_posts = ForumThread.find(params[:id])
#forum_posts = ForumPost.paginate(:page => params[:page], :per_page => 3)
end
You're paginating the equivalent of ForumPost.all, which means you're going to get back all the posts, regardless of which thread they're a part of.
You need:
def show
#forum_post = ForumPost.new
#forum_thread = ForumThread.find params[:id]
#forum_posts = #forum_thread.paginate(page: params[:page], per_page: 3)
end
This is assuming you have the following setup:
#app/models/forum_thread.rb
class ForumThread < ActiveRecord::Base
has_many :forum_posts
end
#app/models/forum_post.rb
class ForumPost < ActiveRecord::Base
belongs_to :forum_thread
end
As an aside (this is advanced), you'd be much better putting your thread and post models into a Forum module:
#app/models/forum.rb
class Forum < ActiveRecord::Base
has_many :threads, class_name: "Forum::Thread"
end
#app/models/forum/thread.rb
class Forum::Thread < ActiveRecord::Base
belongs_to :forum
has_many :posts, class_name: "Forum::Post"
end
#app/models/forum/post.rb
class Forum::Post < ActiveRecord::Base
belongs_to :thread, class_name: "Forum::Thread"
end
This would allow you to use the following:
#config/routes.rb
scope path: ":forum_id", as: "forum" do
resources :threads do
resources :posts
end
end
#app/controllers/forum/threads_controller.rb
class Forum::ThreadsController < ApplicationController
def show
#forum = Forum.find params[:id]
#threads = #forum.threads
end
end
This is how I got it working.
#forum_posts = #forum_thread.forum_posts.paginate(:page => params[:page], :per_page => 2)
We are looking to have Sender and Receiver attributes for each micropost that is entered on our site. The sender of the post, and the receiver whom it is directed to.
In other words, on each micropost that each user sees, we want the content, and just above or below the content of the post we want the sender shown and receiver shown. We also want users to be able to click on either the sender or the receiver and be linked directly to that profile.
How can we go about doing this? We are relatively new to rails and think additions need to be made in the Micropost model for this change to work. Or should the changes be made in the MicropostsController?
Micropost Model:
class Micropost < ActiveRecord::Base
attr_accessible :content, :belongs_to_id
belongs_to :user
validates :content, :presence => true, :length => { :maximum => 240 }
validates :user_id, :presence => true
default_scope :order => 'microposts.created_at DESC'
# Return microposts from the users being followed by the given user.
scope :from_users_followed_by, lambda { |user| followed_by(user) }
private
# Return an SQL condition for users followed by the given user.
# We include the user's own id as well.
def self.followed_by(user)
following_ids = %(SELECT followed_id FROM relationships
WHERE follower_id = :user_id)
where("user_id IN (#{following_ids}) OR user_id = :user_id",
{ :user_id => user })
end
end
MicropostsController:
class MicropostsController < ApplicationController
before_filter :authenticate, :only => [:create, :destroy]
def create
#micropost = current_user.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Posted!"
redirect_to current_user
else
#feed_items = []
render 'pages/home'
end
end
def destroy
#micropost.destroy
redirect_to root_path
end
end
To eliminate some confusion and make it a bit more railsy, I'd go with:
class Micropost < ActiveRecord::Base
belongs_to :sending_user, :class_name=>"User", :foreign_key=>"user_id"
belongs_to :receiving_user, :class_name=>"User", :foreign_key=>"belongs_to_id"
end
this will allow something like this in your view for a given Micropost object "#micropost":
<%= link_to(#micropost.sending_user.username, user_path(#micropost.sending_user)) %>
<%= link_to(#micropost.receiving_user.username, user_path(#micropost.receiving_user)) %>
*this assumes several things about the user object and routing, but should get you on the right path.