I'm using Couchrest_model as a Rails ORM to CouchDB. I want to have Rails do a "join" of information from two different CouchDB documents for a view, but can't seem to get Rails to auto-retrieve the joined data.
Here's the two related models:
class Package < CouchRest::Model::Base
belongs_to :vendor
property :shortcode, String
property :pins, Integer
end
class Vendor < CouchRest::Model::Base
property :vendor, String
timestamps!
end
So, now in my index.html.erb for /packages I want to display a table with the data from my two models:
<h1>Listing packages</h1>
<table>
<tr>
<th>Shortcode</th>
<th>Pins</th>
<th>Vendor</th>
<th></th>
</tr>
<% #packages.each do |package| %>
<tr>
<td><%= package.shortcode %></td>
<td><%= package.pins %></td>
<td><%= package.vendor %></td>
<td><%= link_to 'Show', package %></td>
<td><%= link_to 'Edit', edit_package_path(package) %></td>
<td><%= link_to 'Destroy', package, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Package', new_package_path %>
I want to display the vendor string from the Vendor model. I've used a selector helper in a view to display "joined" information across models with CouchDB, but I can't figure out how to join in this seemingly simpler case of just printing the string in the view table.
Here's the Package controller that corresponds to the index, which is pretty standard:
class PackagesController < ApplicationController
# GET /packages
# GET /packages.json
def index
#packages = Package.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #packages }
end
end
I've tried doing the standard
#packages = Package.all(:include => :vendor)
but Couchrest_model doesn't pull in the vendor information that way...
I am not sure if I understand your question, but you want to get the vendor string from the instance of Vendor which is attached to your package instance? Just use #package.vendor.vendor
There is no (easy) way to include the vendor record while fetching all packages, so that you only have to make 1 request. You have to fetch the vendor after you fetched all packages because CouchDD does not support document linking or joins. If you have for example 100 packages and want to fetch the vendor string from all attached vendors you end up with a typical n+1 situation (100+1 requests). 1 request to fetch all packages and 100 for each vendor. A better solution is to get all keys of all vendors after the first request and fetch all vendors in a second request using the "keys" parameter while fetching. (Documentation)
I hope i could help you.
Related
Filter with another table's attribute (one to many) in Rails
I'm a beginner on rails and currently working on my class project. I have a lead and a lead_comments table, lead has_many lead_comments and lead_comment belong_to lead, which I got those established.
In Model:
class Lead < ApplicationRecord
has_many :lead_comments
end
class LeadComment < ApplicationRecord
belongs_to :lead
end
In my lead's index view, I am trying to setup a date filter base on the Update_at in the lead_comments, which is the attribute from another table:
<div class="date-search">
<%= form_tag leads_path, method: :get do %>
<%= date_field_tag 'date_search[date_from]', #date_search.date_from %>
<%= date_field_tag 'date_search[date_to]', #date_search.date_to %>
<%= submit_tag 'Date Search' %>
<% end %>
</div>
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Phone Number</th>
<th>Last Updated Date</th>
<th colspan="3">Action</th>
</tr>
</thead>
<tbody>
<% #leads.each do |lead| %>
<tr>
<td><%= lead.lead_firstname %></td>
<td><%= lead.lead_lastname %></td>
<td><%= lead.lead_phone %></td>
<td><%= lead.lead_comments.maximum(:updated_at) %></td>
<td><%= link_to 'Detail', lead %></td>
<td><%= link_to 'Edit/Update', edit_lead_path(lead) %></td>
<td><%= link_to 'Remove', lead, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
In my lead controller, I set up another controller for lead search purpose:
def index
#date_search = LeadSearch.new(params[:date_search])
#leads = #date_search.scope
end
In my lead search model, I believe where my problem is:
class LeadSearch
attr_reader :date_from, :date_to
def initialize(params)
params ||= {}
#date_from = parsed_date(params[:date_from], 30.days.ago.to_date.to_s)
#date_to = parsed_date(params[:date_to], Date.today.to_s)
end
def scope
Lead.lead_comments.maximum(:updated_at).where('updated_at BETWEEN ? AND ?', #date_from, #date_to)
end
private
def parsed_date(date_string, default)
Date.parse(date_string)
rescue ArgumentError, TypeError
default
end
end
My lead_comment table only has one attributes, which is comment, along with the two automated date attributes created by Rails, created_at and updated_at.
Whenever I run the application I get an error that tells me undefined method "lead_comments". I thought I have already established the has_many and belong_to relationship and this still not working. Can someone please help me out and guide me to the right direction? Thank you for your time.
you are doing Lead.lead_comments which is wrong. You are using the class name instead of the object. There should be a Lead model's object.
#lead.lead_comments
First, try your query in rails console. then use it in the controller for better perspective. try following,
Lead.lead_comments # will give error
instead use,
Lead.last.lead_comments # success
Issues in your code:
Lead.lead_comments
Let's simplify this: think about lead_comments as a method that given a lead returns its comments. But we need a lead. That's why called on Lead does not work. That would work called on a Lead object.
Lead.lead_comments.maximum(:updated_at)
Here you're composing a SQL query though ActiveRecord but calling maximum stop this composition because that require a value so you're not able to call anything else after methods like maximum
Let's make your code work
def scope
Lead.where('updated_at BETWEEN ? AND ?', #date_from, #date_to)
end
in your view
<td><%= lead.lead_comments.maximum(:updated_at) %></td>
Note here that this code has always been correct because you call lead_comments on a lead object.
I know, this performs one query for each Lead object but to make it works with just one query looks like another question
I am new to Rails 5 and working on a project where in there is a page for each categories and will only show the blog items with specific or same categories.
For instance: Blog Title 1 to Blog Title 5 has a category "Tech" and Blog Title 6 to Blog Title 8 has a category "Business".
If I click on http://localhost:3000/blogs/tech it will show the Blog Title 1 to 5 and if I click on http://localhost:3000/blogs/business it will show the Blog Title 6 to 8.
To do these what I've tried is create custom scope on my blogs controller:
class BlogsController < ApplicationController
def index
#blogs = Blog.all
end
def business
#blogs = Blog.business
end
end
And then on my blog model:
class Blog < ApplicationRecord
def self.business
where(post_category: 1)
end
end
I also created a new view for my business method to show all the business type category blog items and just copied the same content on my index.html.erb file:
<p id="notice"><%= notice %></p>
<h1>Post Category 0</h1>
<table>
<thead>
<tr>
<th>Title</th>
<th>Body</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #blogs.each do |blog| %>
<tr>
<td><%= blog.title %></td>
<td><%= blog.body %></td>
<td><%= link_to blog.status, toggle_status_blog_path(blog) %></td>
<td><%= blog.post_category.title %></td>
<td><%= link_to 'Show', blog %></td>
<td><%= link_to 'Edit', edit_blog_path(blog) %></td>
<td><%= link_to 'Destroy', blog, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Blog', new_blog_path %>
And finally I updated my routes:
get 'blogs/business', to: 'blogs#business'
While this will work for single items. Putting it manually wont work if each time I create a new category plus I don't know exactly what will be the user of the app will add on the category title. How can I do this programmatically so it will create new pages each time a new category is being created instead of adding manually and creating views each time?
Are there any ways to do these?
Side Note: Blog and PostCategory table are related to each each other via post_category_id.
You do not have to use scopes here. Just use BlogsController#show to display posts from a given category.
Start with adding a slug field for the PostCategory (in the database). Right now you are using title in the URL, but it has to be changed to escaped value (without spaces, special characters, etc.).
You can probably do it with a gem, or you can use the code from my gist. Just remember to adjust it to your model and fields.
Then, add a route (routes.rb):
get 'blog/:slug', to: 'blogs#show', as: :blog_category
Finally, in your BlogsController, add show method:
def show
category = PostCategory.find_by(slug: params[:slug])
#blogs = Blog.where(post_category: category.id)
end
That's all. Of course, you can modify show by permitting params, adding joins and doing a single query for fetching blogs, but this can be done later.
I'm new to RoR, so please be gentile. I'm not sure, if I search for the right topic. However, I've spent the whole day trying to figure out, how to work with the has_man, belongs_to and so forth asset associations.
Right now I have two assets:
sqlite> pragma table_info(meetups);
0|id|INTEGER|1||1
1|name|varchar(255)|0||0
2|owner|integer|0||0
3|dateOfInception|datetime|0||0
4|homeTown|varchar(255)|0||0
5|created_at|datetime|0||0
6|updated_at|datetime|0||0
7|activity_id|integer|0||0
sqlite> pragma table_info(activities);
0|id|INTEGER|1||1
1|name|varchar(255)|0||0
2|location|varchar(255)|0||0
3|startDate|datetime|0||0
4|duration|integer|0||0
5|description|varchar(255)|0||0
6|created_at|datetime|0||0
7|updated_at|datetime|0||0
8|image|varchar(255)|0||0
9|meetup_id|integer|0||0
So I can create a new meetup and select multiple saved activities. For every meetup we can select a multiple activities. If I create a meetup, they corresponding activities are also stored correctly, as you can see in the image below:
Image
However, it's not useful to output them just like an array. It would be great, if the activity name would appear. But how is that possible? I tried so many things, renaming the db foreign keys, create a find method in the meetup controller... but nothing worked. Please help me out here - I think I'm very near but someting I dont know doesnt work.
<% #meetups.each do |meetup| %>
<tr>
<td><%= meetup.name %></td>
<td><%= meetup.owner %></td>
<td><%= meetup.dateOfInception %></td>
<td><%= meetup.homeTown %></td>
<td><%= meetup.activity_ids %></td>
<td><%= link_to 'Show', meetup %></td>
<td><%= link_to 'Edit', edit_meetup_path(meetup) %></td>
<td><%= link_to 'Destroy', meetup, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
class MeetupsController < ApplicationController
before_action :set_meetup, only: [:show, :edit, :update, :destroy]
# GET /meetups
# GET /meetups.json
def index
#meetups = Meetup.all
end
Many thanks for your help!
Try this in your view:
meetup.activities.map(&:name).join(',')
That should show the data you want. For performance reasons, you'll want to add .include(:activities) to
the controller action that loads your list of meetups.
It sounds like you're trying to model a Has And Belongs To Many relationship, though? You'll need a third table to model that correctly.
If that's not what you're wanting to model, you should remove the activity_id column from the meetups table.
I'm new to ruby and picking it up a little slower than I would like. I'm working with ruby 3.0. For one of my tables in the database I created I want the primary key to show on the "index" page. I'm having difficulty doing this. I manually put the id in the index view, but it keeps on saying "undefined method `venture_round_id'"
This is what my index.html looks like for the table:
<h1>Listing venture_rounds</h1>
<table>
<tr>
<th>id</th>
<th>company</th>
</tr>
<% #venture_rounds.each do |venture_round| %>
<tr>
<td><%= venture_round.venture_round_id %></td>
<td><%= venture_round.company_id %></td>
<td><% link_to 'show', venture_round %></td>
<td><%= link_to 'Edit', edit_venture_round_path(venture_round) %></td>
<td><%= link_to 'Destroy', venture_round, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
I entered "venture_round_id" and "id" in manually.
This is what my controller looks like for the index:
def index
#venture_rounds = VentureRound.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #venture_rounds }
end
end
I've been researching this problem for two days now and haven't been able to find much about it. I imagine the problem has something to do with accessing the key in its own table. Other parts of my database structure that use venture_round_id as a foreign key work just fine. Any pointers or tips would be greatly appreciated!
Try venture_round.id instead of venture_round.venture_round_id
edit from MrDanA:
a foreign key is usually in the format "table_id" but the table's own primary key is usually just "id". If you ever want to look at what your database tables look like, you can open db/schema.rb to look at the schema. You can also fire up a Rails console and if you just type in the name of your class like VentureRound it will show you its attributes, something like VentureRound(id: integer, company_id: integer, etc)
I'm doing an online judge application, so I have a User model, a Problem model and a Solution model to make the many to many relation. In that Solution model I have an extra column called "state" where I plan to store the state of a problem for a certain user: solved, wrong anwser, not solved.
I'm trying to modify the index action in my problems controller to render the state of the problem in the problem list (so a user can see if he has solved a problem or not, like I said before). Nevertheless I'm having an "uninitialized constant Admin::ProblemsController::Solution" error when I access the view.
I'm really new to RoR and my experience so far has been really harsh, so I'll appreciate any leads. Here is the code in the controller and the view:
problems_controller.rb
def index
#problems = Problem.all
if current_user
#solutions = Solution.includes(:problem).where(:user_id => current_user.id)
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #problems }
end
end
views/problems/index.html.erb
<% #problems.each do |problem| %>
<tr>
<td><%= problem.name %></td>
<td><%= problem.code %></td>
<td><%= problem.description %></td>
<% if current_user %>
<%= for solution in #solutions do %>
<% if solution %>
<td><%= solution.state%></td>
<% else %>
<td>Not Solved</td>
<% end %>
<% end %>
<% end %>
<td><%= link_to 'Show', problem %></td>
<% if current_user && current_user.is_admin? %>
<td><%= link_to 'Edit', edit_problem_path(problem) %></td>
<td><%= link_to 'Delete', problem, method: :delete, data: { confirm: 'Are you sure?' } %></td>
<% end %>
</tr>
<% end %>
I'm not sure if that's the best way I should be accessing the Solutions table or if I should be doing that in another controller (in the users controllers? in a solutions controller file perhaps?).
I want to be clear of how to use that "Solutions" join table. I had a has_and_belongs_to_many before and changed it because of the extra column. I've read a lot about many to many relationships, but I can't understand it for this case =(
Just need to use:
problem.solution.state
Unless a problem may have many solutions, then it would need to be something like:
problem.solutions.first.state
However this will just give the state of the first, so I'd define a method in Problem which calculates a status (eg. If any of the solutions solve it then problem is solved)
For 1 problem, many solutions for a given user.
In Solution.rb
scope :for_user, lambda {|user_id| :conditions => {:user_id => user_id}}
Then we can call:
problem.solutions.for_user(current_user.id).first.state
It might look a bit long but it's highly flexible.