In my movie model, I have the following code.
class Movie < ApplicationRecord
belongs_to :user
has_many :reviews, dependent: :destroy
has_many :users, through: :reviews
validates :title, :description, :movie_length, :director, :rating, presence: true
end
def self.show_order_desc
self.review.order("created_at DESC")
end
And I'm calling this in my movie controller show action where I have my reviews for that movie.
def show
#reviews = show_order_desc
end
is this the right way? is this a scope? it's working but I have a review coming along and I want to be sure to past this feature.
I think you are trying to fetch all reviews of a movie in descending order of created_at. You can follow bellow codes.
# app/models/movie.rb
class Movie < ApplicationRecord
belongs_to :user
has_many :reviews, dependent: :destroy
has_many :users, through: :reviews
validates :title, :description, :movie_length, :director, :rating, presence: true
end
# app/models/review.rb
class Review < ApplicationRecord
belongs_to :movie
belongs_to :user
scope :created_desc, -> { order(created_at: :desc) }
end
# app/controllers/movies_controller.rb
class MoviesController < ApplicationController
before_action :find_movie, only: [:show] # you can add other actions also
def show
#reviews = #movie.reviews.created_desc
end
# your other actoins
private
def find_movie
#movie = Movie.find(params[:id])
end
end
Here I have added one scope in Review model which will order reviews as per your requirement. Now in the show action I am fetching reviews of a movie first, then using the scope for against those reviews to order in descending order with created_at.
Related
I'm trying to figure out how to automatically set up an invoice with invoice_rows, once a reservation is saved.
Attempts
Before even including the order_rows, I tried generating an invoice for order:
I tried including #order.invoices.create(order_contact_id: #order.order_contact_id) after saving the order in create, but this resulted in an empty array:
Order.last.invoice => []
Afterwards I probably should iterate over all products belonging to a order and include them as invoice_rows in invoice. But not sure how.
Note
The actual structure is more complex and consequently I need all my tables.
Code
models
class Order < ApplicationRecord
has_many :invoices
has_many :order_products, dependent: :destroy
end
class OrderProduct < ApplicationRecord
belongs_to :product
belongs_to :order
accepts_nested_attributes_for :product
end
class Product < ApplicationRecord
has_many :orders, through: :order_products
has_many :product_prices, dependent: :destroy, inverse_of: :product
accepts_nested_attributes_for :product_prices, allow_destroy: true
end
class ProductPrice < ApplicationRecord
belongs_to :product, inverse_of: :product_prices
end
orders_controller
class OrdersController < ApplicationController
def create
#order = #shop.orders.new(order_params)
authorize #order
if #order.save
authorize #order
# #order.invoices.create(order_contact_id: #order.order_contact_id)
redirect_to new_second_part_shop_order_path(#shop, #order)
end
end
private
def order_params
params.require(:order).permit(:order_contact_id,
order_products_attributes: [:id, :product_id, :product_quantity, :_destroy,
products_attributes: [:id, :name, :description]])
end
end
As suggested in the comments, I found the error message by using #order.invoices.create!.
Afterwards I iterated over each product and created an invoice_row for the created invoice.
#invoice = #order.invoices.create!(order_contact_id: #order.order_contact_id)
#order.order_products.each do |o_product|
#invoice.invoice_rows.create!(
description: o_product.product.name,
total_price: #reservation.total_product_price(#reservation, o_product)
)
end
I have nested relationships and built them according to the Rails Guide.
A User has many Collections that have many Sections each containing many Links. When creating a new Link though, the user_id is not being assigned but is always nil. The section_id and collection_id are being set correctly.
Controller
class Api::V1::LinksController < Api::V1::BaseController
acts_as_token_authentication_handler_for User, only: [:create]
def create
#link = Link.new(link_params)
#link.user_id = current_user
authorize #link
if #link.save
render :show, status: :created
else
render_error
end
end
private
def link_params
params.require(:resource).permit(:title, :description, :category, :image, :type, :url, :collection_id, :user_id, :section_id)
end
def render_error
render json: { errors: #resource.errors.full_messages },
status: :unprocessable_entity
end
end
Models
User
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
acts_as_token_authenticatable
has_many :collections, dependent: :destroy
has_many :sections, through: :collections, dependent: :destroy
has_many :links, through: :sections, dependent: :destroy
mount_uploader :image, PhotoUploader
end
Collection
class Collection < ApplicationRecord
belongs_to :user
has_many :sections, dependent: :destroy
has_many :links, through: :sections, dependent: :destroy
mount_uploader :image, PhotoUploader
end
Section
class Section < ApplicationRecord
belongs_to :collection
has_many :links, dependent: :destroy
end
Link
class Link < ApplicationRecord
belongs_to :section
end
Is this the correct way to set up the relationships and can someone help me understand what I am missing?
You can't do
#link.user_id = current_user
You could (instead) do...
#link.user_id = current_user.id
Or more elegantly...
#link.user = current_user
Which assumes you will define the relationship in the model
class Link < ApplicationRecord
belongs_to :section
belongs_to :user
end
But as Andrew Schwartz points out in the comments, it may have been a design mistake to add the field user_id to the links table. You have in the User model has_many :links, through: :sections, dependent: :destroy which does not use any user_id field in the link record. It uses the user_id field in the collections table
Just adding user_id to the links table will NOT mean that link will be returned when you do my_user.links ... it won't be.
Since you're passing a section_id in the link_params that is enough to create the link to the user, so just write a migration to remove the user_id field. If you want to be able to see the associated user from the link, do...
class Link < ApplicationRecord
belongs_to :section
has_one :collection, through: :section
has_one :user, through: :collection
end
and that will let you do my_link.user to retrieve the link's user.
I Using accepts_nested_attributes_for to update has_many nested tables, Why not update but insert
diaries_controller.rb
def update
#diary=Diary.find(params[:id])
if #diary.update(update_diary_params)
render_ok
else
render_err :update_error
end
end
def update_diary_params
params.require(:diary).permit(:date,:weather,:remark, :diary_pictures_attributes=> [:diary_picture,:clothing_picture,:id,:_destroy])
end
model/diary.rb
class Diary < ApplicationRecord
has_many :diary_pictures,dependent: :destroy
accepts_nested_attributes_for :diary_pictures,allow_destroy: true
end
model/diary_picture.rb
class DiaryPicture < ApplicationRecord
belongs_to :diary
validates_presence_of :diary
end
enter image description here
Simple problem I can't figure out.
How do you get a list of associated items that are associated with a list of another type of item. For example a Clinician has_many patients through care_group_assignments and patients has_many assessments. I want a list of patients to give me a list of all of their assessments. #patients gives me the list of patients; how do I get their lists of assessments? I want #assessments to be a list of all of the assessments associated with all of the patients associated with a given clinician.
I have a has_many :through relationship between 'Clinician', and 'Patient' with a joined model 'CareGroupAssignment'.
clinician.rb (simplified)
class Clinician < ActiveRecord::Base
has_many :patients ,:through=> :care_group_assignments
has_many :care_group_assignments, :dependent => :destroy
has_many :assessments, :through => :patients
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
patient.rb
class Patient < ActiveRecord::Base
has_many :clinicians ,:through=> :care_group_assignments
has_many :care_group_assignments
has_many :assessments, dependent: :destroy
belongs_to :user
accepts_nested_attributes_for :user, :allow_destroy => true
end
care_group_assignments.rb
class CareGroupAssignment < ActiveRecord::Base
belongs_to :clinician
belongs_to :patient
end
I tried using answers from 4720492, 9408931, and 15256541.
I am trying to get the list in the ClinicianController:
def show
#clinician = Clinician.find_by(id: params["id"])
#patients = #clinician.patients
#assessments = #patients.assessments.order("created_at desc")
end
current_clinician is defined in my ApplicationController as:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user
before_action :require_user
helper_method :current_clinician
before_action :require_clinician
def current_user
#current_user ||= User.find_by!(auth_token: cookies[:auth_token]) if cookies[:auth_token]
end
def require_user
if current_user.nil?
redirect_to new_session_path
end
end
def current_clinician
current_user.clinician
end
def require_clinician
if current_clinician.nil?
redirect_to new_session_path
end
end
end
Right now I get a NoMethodError in CliniciansController#show,
undefined method `assessments' for #Patient:.....
Rails 4.1.8, ruby 2.2.1p85, PostgreSQL
Thanks
Have you tried #clinician.assessments? You should be able to get the results you want through the magic of AR and join tables!
According your Patient model, Patient has_many assessments but in action show you use:
#assessments = #patients.assessments.order("created_at desc")
Where #patients - list of items of the model Patient.
You should refactor you logic there.
Try to do this:
#assessments = Assessment.joins(:patient => {:care_group_assignments => :clinician).where(["clinicians.id = ?", #clinician.id]).order("assessments.created_at desc")
I hope this help you.
So the way I did things for these model set ups is a bit different then what you might actually do. How ever I did things like this:
Post Model
class Post < ActiveRecord::Base
belongs_to :blog
belongs_to :user
has_and_belongs_to_many :tags, join_table: 'tags_posts', :dependent => :destroy
has_and_belongs_to_many :categories, join_table: 'categories_posts', :dependent => :destroy
has_many :comments, :dependent => :destroy
validates :title, presence: true
def has_tag?(tag_name)
tags.where(name: tag_name).any?
end
def tag_names
tags.pluck(:name)
end
def tag_names=(names)
self.tags = names.map{ |name| Tag.where(name: name).first }
end
def tag_name=(tag_name)
single_tag = [tag_name]
self.tag_names = single_tag
end
def has_category?(category_name)
categories.where(name: category_name).any?
end
def category_names
categories.pluck(:name)
end
def category_names=(names)
self.categories = names.map{ |name| Category.where(name: name).first }
end
def category_name=(category_name)
single_category_name = [category_name]
self.category_names = single_category_name
end
def user=(id)
user = User.find_by(id: id)
self.user_id = user.id if user
end
end
The above allows us to assign tags and categories and a post to a user (the last part is being refactored out as we speak). You can also get all tags and categories for a post and see if that post has a particular category.
Now what I want to do, in the tags model (for now) is get all the posts that a tag belongs to. But I am not sure how to do that ...
this is my tags model:
Tags Model
class Tag < ActiveRecord::Base
belongs_to :blog
validates :name, presence: true, uniqueness: true
end
How do I accomplish what I want?
I am not sure how to do this with has_and_belong_to_many. However, it would be pretty easy using has many through. By Rails conventions, the same of your join table should be tag_posts or post_tags (the first model is singular).
In your Post model:
has_many :tag_posts
has_many :tags, :through => :tag_posts
Then in your Tag model, a similar setup:
has_many :tag_posts
has_many :posts, :through => :tag_posts
Finally, you would create a TagPost model
belongs_to :tag
belongs_to :post
After that, calling tag.posts should return all posts for a given tag.