ely_you
ely_you

Reputation: 9

How to merge two objects in Ruby on Rails

I'm trying to retrieve from the database two contents: the first one with the field source equal to "imported" (which means that we import it from the excel spreadsheet), and the second one with source != imported (we create it from scratch). Attached is my code:

def index
    add_breadcrumb 'Projects', projects_path
    add_breadcrumb @project.name, @project
    add_breadcrumb "List #{@category.display_name} Content",    project_category_contents_path(@project, @category)
    @contents_imported = Content.of_project(@project).with_category(@category).imported.order('contents.created_at asc')
    @contents_not_imported = Content.of_project(@project).with_category(@category).not_imported.order('contents.created_at desc')
    @page = params[:page]
    @contents = @contents_not_imported << @contents_imported    
    @q = @contents.search(params[:q])
    @content = @q.result(distinct: true).page(@page).per(20)
end

@contents_imported = Content.of_project(@project).with_category(@category).imported.order('contents.created_at asc')

@contents_not_imported = Content.of_project(@project).with_category(@category).not_imported.order('contents.created_at desc')

And I want to combine the two results before showing it:

@contents = @contents_not_imported << @contents_imported 

but it didn't work. How can I do that?

Upvotes: 0

Views: 1578

Answers (4)

Alejandro Babio
Alejandro Babio

Reputation: 5229

Just create a new Relation with the conditions of imported or not imported, after that, order all the records (if order is important to @contents and @content):

def index
  add_breadcrumb 'Projects', projects_path
  add_breadcrumb @project.name, @project
  add_breadcrumb "List #{@category.display_name} Content", project_category_contents_path(@project, @category)
  @contents_imported = Content.of_project(@project).with_category(@category).imported.order('contents.created_at asc')
  @contents_not_imported = Content.of_project(@project).with_category(@category).not_imported.order('contents.created_at desc')
  @page = params[:page]

  imported = @contents_imported.where_values.reduce(:and)
  not_imported = @contents_not_imported.where_values.reduce(:and)

  @contents = Content.where(imported.or(not_ipmorted)).order('CASE contents.imported WHEN true THEN contents.created_at asc ELSE contents.created_at desc END')

  @q = @contents.search(params[:q])
  @content = @q.result(distinct: true).page(@page).per(20)
end

Now you can call Ransack#search on @contents because it is an ActiveRecord::Relation. I assume that the imported scope take a field contents.imported with value true.

If I wrote this without errors, this must works.

Upvotes: 0

PinnyM
PinnyM

Reputation: 35533

The problem is that you want to concatenate results, but you also want to continue treating the combined results as an ActiveRelation (call .search on it). Here's a simpler approach that avoids the need for concatenation in the first place. You will need a more complex ORDER BY clause to accomplish this, however:

@page = params[:page]
@contents = Content.of_project(@project).with_category(@category).
  order('CASE WHEN source <> "imported" THEN contents.created_at END desc, CASE WHEN source = "imported" THEN contents.created_at END asc')
@q = @contents.search(params[:q])

Upvotes: 1

Sonalkumar sute
Sonalkumar sute

Reputation: 2575

Concatenating the arrays is done with the plus sign

You are getting undefined method search for Array because, concatenating will return you an array. And you can't call search method on that Array

EDIT

def index
    add_breadcrumb 'Projects', projects_path
    add_breadcrumb @project.name, @project
    add_breadcrumb "List #{@category.display_name} Content",      project_category_contents_path(@project, @category)
    contents_imported_ids = Content.of_project(@project).with_category(@category).imported.order('contents.created_at asc').map(&:id)
    contents_not_imported_ids = Content.of_project(@project).with_category(@category).not_imported.order('contents.created_at desc').map(&:id)
    @page = params[:page]
    contents_ids = contents_imported_ids + contents_not_imported_ids 
    contents = Content.where(content_ids)
    @contents = content_ids.collect{|id| contents.detect{|c| c.id == id}}
    @q = @contents.search(params[:q])
    @content = @q.result(distinct: true).page(@page).per(20)
end

Upvotes: 0

AshwinKumarS
AshwinKumarS

Reputation: 1313

If both of them are arrays and are having same type of objects you can do Result = Arr1 | Arr1

That also removes the duplicates. Its like boolean UNION. In your case @contents = @contents_not_imported | @contents_imported

Upvotes: 1

Related Questions