refactoring a controller query with If/else - ruby-on-rails

This is what my index action currently looks like. If the current_user is not enrolled to any courses it lists all courses. If he is enrolled to any, it only lists the other ones. Is this a good way to get the needed records or is there a nicer way? Any suggestions? Thx for your time!
if current_user.courses.empty?
#courses = Course.all
else
#courses = Course.where("id not in (?)", current_user.courses)
end

Use:
#user = current_user
#courses = #user.courses.empty? ? Course.all : Course.where("id not in (?)", #user.courses)

You could move all of this logic into a method on user:
class User < ActiveRecord::Base
def courses
if self.courses.empty?
#courses = Course.all
else
#courses = Course.where("id not in (?)", current_user.courses)
end
end
end
Then in your controller:
#courses = current_user.courses
You may also want to re-examine your schema and possibly get rid of the if/else altogether.

Related

Rails: Show all posts except last post

I have created a section for my latest posts, and a section for all posts. However, my last created post gets shown twice.
In my controller, how do I show all posts except for the last post?
MainController
def index
#post = Post.all.order('created_at DESC')
#latest_post = Post.ordered.first
end
You're querying twice. Instead, query once, and pull the latest post off the result set:
def index
#posts = Post.all.order('created_at DESC').to_a
#latest_post = #posts.pop
end
I'm not completely sure which side of the results you're considering the "first" record, so if #posts.pop appears to give you what you consider the "last" record then use #posts.shift to remove the record from the opposite end.
This will not fetch #latest_post in #post
def index
#latest_post = Post.ordered.first
#post = Post.where.not(id: #latest_post.id).order('created_at DESC')
end
Or simply
def index
#latest_post = Post.last
#posts = Post.where.not(id: #latest_post.id).order('created_at DESC')
end

Rails 4: how to include selected association in searching/filtering a model entity

First of all, I am totally new to Rails and still on the steep learning curve. I recently took over a rails project and need to do some tweaking on the existing code.
I need to include an association named 'School' when searching/filtering the model named 'Teacher'. A teacher has_many schools.
In the search method of the teacher controller, I have the following:
def search
if params[:id].present? || params[:city].present?
#teachers = Teacher.include(:schools).all
#teachers = #teachers.matches('id', params[:id]) if params[:id].present?
#teachers = #teachers.matches('name', params[:city]) if params[:city].present?
else
#teachers = []
end
end
However, the .include(:schools) does not work for me. I also tried to use .eager_loading(:schools), but does not work either.
Maybe try something like:
def search
if params[:id].present? || params[:city].present?
#teachers = Teacher.includes(:schools)
if params[:id].present?
#teachers = #teachers.find params[:id]
elsif params[:city].present?
#teachers = #teachers.find_by_name params[:city]
end
else
#teachers = []
end
end
I think you are using include instead of includes. See here.

Multiple Filters in Rails: Category and Location

I currently have an app where a book entry belongs_to a category and a category has_many books. sample:
Book: Category:
Book1 Elementary
Book2 Elementary
Book3 HighSchool
Book4 College
I would like to build a new Location Model where I can be able to show i.e: all Elementary books under a state or can go down further to a City.
this is how my current index controller looks like:
def index
if params[:category].blank?
#book = Book.all.order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#book =Book.where(category_id: #category_id).order("created_at DESC")
end
end
I was thinking of doing something like:
def index
if params[:category].blank?
#book = Book.all.order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#location_id = Location.find_by(name: params[:location]).id
#book =Book.where(category_id: #category_id, location_id: #location_id).order("created_at DESC")
end
end
Is this correct?
I'm fairly new in Rails and Relational Databases and I'm having a hard time conceptualizing how this'll work. Please let me know if you need more information. Any assistance on this topic will be highly appreciated.
Thank you,
Mike B.

Rails: Displaying published post by all and unpublished post of current_user

I wanted to know how one would do the following:
A user can view all published Posts
A user can view view their unpublished Post
Code:
# Post model
scope :published, where(is_published: true)
scope :unpublished, where(is_published: false)
# Post controller
def index
#Post = Post.published
if user_signed_in?
#Post = Post.published && Post.unpublished.where(user_id: current_user.id)
end
end
I'm not really sure what the right way to setup an active record condition to display what I'm after.
Any much is much appreciated.
You're pretty close! Just replace && with +
# Post controller
def index
#posts = Post.published
if user_signed_in?
#posts = Post.published + Post.unpublished.where(user_id: current_user.id)
end
end
Be aware that joining like this will change the #posts object from a relation to an array.
Also take a look at #SachinR's answer for a nice refinement to the Post.unpublished.where(user_id: current_user.id) line.
Based on your requirement I think you could do better with a scope:
#Post model
scope :published_and_user, lambda{|user| where("is_published = ? OR user_id = ?", true, user.id)}
scope :ordered, :order => "created_at DESC"
# Post controller
def index
#posts = Post.published.ordered
if user_signed_in?
#posts = Post.published_and_user(current_user).ordered
end
end
And now you have a relation that is ordered properly, and only one scope!
To get all published records
#posts = Post.where("user_id = ?", current_user.id).published
To get all unpublished records
#posts = Post.where("user_id = ?", current_user.id).unpublished
or
If Post belongs to user
class Post
belongs_to :user
end
then you can directly use
current_user.posts.published
current_user.posts.unpublished

rails controller for mixed nested and non-nested resources

I'm working on a blog like application,
my user module has_many posts and the posts module belongs_to user
I want to access both users/:id/posts and posts/
routes.rb is something like this:
resources :users do
resources :posts
end
resources:posts
how can i know within the posts controller if its accessed directly (/posts) or through the nested route (/users/:id/posts) ?
for example, what should be the index method of the posts controller for doing the correct INDEX action for /users/:id/posts and for /posts
is there a better way for doing this ?
One solution could be to use a before filter on your controller, like:
before_filter :load_user
def load_user
#user = User.find(params[:user_id]) if params[:user_id]
#posts = #user ? #user.posts : Post.all
end
Then you have to rewrite your controller a bit to function properly.
No refactoring needed on index action, #posts already loaded correctly, but you can do further filtering as you like
def index
#posts = #posts.where('updated_at < ?' Time.now)
end
Then update every member action: new, create, show, edit, update, destroy and use posts as a base like:
def new
#post = #posts.build
end
def create
#post = #posts.build(params[:task])
end
def show
#post = #posts.find(params[:id])
end
def edit
#post = #posts.find(params[:id])
end
def update
#post = #posts.find(params[:id])
end
def destroy
#post = #posts.find(params[:id])
end
Of course you can add other before filters to remove duplicate code.
Check the params.
If just post you'll just have :id
If user/post you'll have user and ID for post.
So check if params[:user]...
n.b. If not user, try params[:user_id]
As for the index method for posts I think it will actually be the SAME in both cases. What will change things is its usage, association and scoping within user.

Resources