I am a newbie at rails and i wanted help on how to merge collections of two active record objects?
An article has many comments
class Article < Content
has_many :comments
I want to create a new article with comments merged from the comments of source and target article objects.Below, source_id and target_id are ids of two Articles. I want to get comments from them and merge them and add to the new article.
source_id = params[:id]
target_id = params[:merge_with]
#article = Article.get_or_build_article()
#article.allow_comments = true
article_source = Article.find(source_id)
article_target = Article.find(target_id)
#reassign all comments of first article
first_comments = article_source.comments
first_comments.each do |c|
c.article_id = #article.id
c.save
end
#reassign all comments of second article
second_comments = article_target.comments
second_comments.each do |d|
d.article_id = #article.id
d.save
end
#article.title = article_source.title
#article.body = article_source.body + " " + article_target.body
#article.author = article_source.author
#article.save
I see that the new article is created but it doesnt display any comments. So, the linking is broken somewhere. I appreciate any help! Thanks!
You have not saved #article in database. So #article.id is nil.
first_comments.each do |c|
c.article_id = #article.id
c.save
end
So this loop, assigns nil to c.article_id. So first save the #article then update comments. Also use update_all for updating comments instead of looping.
source_id = params[:id]
target_id = params[:merge_with]
#article = Article.get_or_build_article()
#article.allow_comments = true
article_source = Article.find(source_id)
article_target = Article.find(target_id)
#article.title = article_source.title
#article.body = article_source.body + " " + article_target.body
#article.author = article_source.author
#article.save
#reassign all comments of first article
first_comments = article_source.comments
first_comments.update_all(article_id: #article.id)
#reassign all comments of second article
second_comments = article_target.comments
second_comments.update_all(article_id: #article.id)
Or even better to update comments use this
Comment.where(article_id: [article_source.id, article_target.id]).update_all(article_id: #article.id)
Related
In a rails 4.1 application I need to add an object to an "AssociationRelation"
def index
employee = Employee.where(id_person: params[:id_person]).take
receipts_t = employee.receipts.where(:consent => true) #gives 3 results
receipts_n = employee.receipts.where(:consent => nil).limit(1) #gives 1 result
#I would need to add the null consent query result to the true consent results
#something similar to this and the result is still an association relation
#receipts = receipts_t + receipts_n
end
Is there a simple way to do this?
A way of solving this:
def index
employee_receipts = Employee.find_by(id_person: params[:id_person]).receipts
receipts_t = employee_receipts.where(consent: true)
receipts_n = employee_receipts.where(consent: nil).limit(1)
#receipts = Receipt.where(id: receipts_t.ids + receipts_n.ids)
end
Unfortunately .or() can't be used here because it's only available from Rails v5.0.0.1
you could do this way
receipts_t_ids = employee.receipts.where(:consent => true).pluck(:id)
receipts_n_ids = employee.receipts.where(:consent => nil).limit(1).pluck(:id)
#receipts = Receipt.where(id: receipts_t_ids + receipts_n_ids)
To avoid extra queries and keeping arrays in memory, you can use or
Like this:
def index
employee_receipts = Employee.find_by(id_person: params[:id_person]).receipts
#receipts =
employee_receipts.where(consent: true).or(
employee_receipts.where(consent: nil).limit(1)
)
end
I have an app with the following structure:
A mealplan includes one recipe for each day of the week.
A recipe has_many ingredients.
A grocery is one item on the user's grocery list.
I want to create a custom method so that when a button is clicked, it runs Grocery.create on each ingredient from the recipes on the mealplan.
I currently have the following mealplans#index method, so you can see how they're defined. (All of this is happening on the index view:
def index
#mealplans = Mealplan.where(user_id: current_user.id)
#mealplan = Mealplan.new
#recent = Mealplan.where(user_id: current_user.id).where("created_at > ?", Time.now.beginning_of_week).order("week_starting").last
#recipes = Recipe.where(user_id: current_user.id)
#monday = Recipe.where(id: #recent.monday)[0] if #recent.present?
#tuesday = Recipe.where(id: #recent.tuesday)[0] if #recent.present?
#wednesday = Recipe.where(id: #recent.wednesday)[0] if #recent.present?
#thursday = Recipe.where(id: #recent.thursday)[0] if #recent.present?
#friday = Recipe.where(id: #recent.friday)[0] if #recent.present?
#saturday = Recipe.where(id: #recent.saturday)[0] if #recent.present?
#sunday = Recipe.where(id: #recent.sunday)[0] if #recent.present?
end
I also have a dummy mealplans#add_to_list method set up in the controller, but I feel like doing it this way violates the "skinny controllers, fat models" principle of rails.
Can anyone clue me in to the "railsiest" way to accomplish this task, according to best practices?
Check gem "nested_form" gem for creating multiple records.
For better implementation create scope under Mealplan model.
class Mealplan < ActiveRecord::Base
scope :recent, ->(uid) { where(user_id: uid).where("created_at > ?", Time.now.beginning_of_week).order("week_starting").last}
# find the day name of recent Mealplan
def recent_day_name
created_at.strftime("%A")
end
end
In controller you can use this scope like this:
def index
#mealplan = Mealplan.new
#recent = Mealplan.recent(current_user.id)
if #recent
recent_day = #recent.recent_day_name
#day = Recipe.find(id: #recent.send(recent_day))
end
end
There is no needs to create #mealplans and #recipes instance variable on controller site:
#mealplans = Mealplan.where(user_id: current_user.id)
#recipes = Recipe.where(user_id: current_user.id)
You can get the mealplans and recipes details from current_user object.
I need a link in a show method of a parent class for creating associated models, so I have the code:
link_to "incomplete", new_polymorphic_path(part_c.underscore, :survey_id => survey.id)
in a helper.
This links to a part, which has new code like this:
# GET /source_control_parts/new
def new
get_collections
if params[:survey_id]
#s = Survey.find(params[:survey_id])
if #s.blank?
#source_control_part = SourceControlPart.new
else
#source_control_part = #s.create_source_control_part
end
else
#source_control_part = SourceControlPart.new
end
end
I know this is not very DRY. How can I simplify this? Is there a RAILS way?
How about this:
def new
get_collections
get_source_control_part
end
private
def get_source_control_part
survey = params[:survey_id].blank? ? nil : Survey.find(params[:survey_id])
#source_control_part = survey ? survey.create_source_control_part : SourceControlPart.new
end
How I can add a model with a model related:
#user = User.find( cookies[:id] )
#u = #user.advert
#advert = #u.create(advert_params)
This model is saved correctly, but when I try to add a model related, but the property town is not updated
#user = User.find( cookies[:id] )
#u = #user.advert
#u.advert.town = Town.find(1)
#advert = #u.create(advert_params)
The relation between advert and town is (1 town has many adverts)
What am I doing wrong?
#u.advert.town = Town.find(1)
But if, as you state:
#u=#user.advert
Then, the first line of this answer translates into
#user.advert.advert.town = Town.find(1)
You should probably do:
#u.town = Town.find(1)
In my controller I'd like to do something like the following:
#book = Book.find(:all, :conditions = > [" created_at > with in the last 1 minute "]
if #book.nil?
# Just incase we didn't create a book, we'll initialize one
#book = Book.create()
end
#chapters = #book.chapters.build etc.............
* In sum, when the user is uploading a chapter, if they've recently created a book, I want the chapter to automatically go to that book and to make a new book.
Thoughts? thank you all
Hi Your code may be something like
time = Time.now
#book = Book.find(:all, :conditions = > [" created_at >= '#{Time.utc(time.year, time.month, time.day, time.hour, time.min - 1)}'"]) // .first if you're sure that it'll return just one record
if #book.blank? //.blank? not .nil? because the result of find is [] not nil
# Just incase we didn't create a book, we'll initialize one
#book = Array.new() //if you're sure that find'll return just one book you may don't change your code here
#book.first = Book.create()
end
//if you're sure that find'll return just one book you may don't change your code here
#book.each do |book|
#chapters = #book.chapters.build etc.............
end
if you're looking for a book created by some user you must pass user_id to this method and your conditions'll be
:conditions = > [" created_at >= '?' AND author_id = ?", Time.utc(time.year, time.month, time.day, time.hour, time.min - 1), params[:author_id]])