So I have this app where I'm using a HABTM association to determine "User Skills"; When a new user is created (via the new user view) the user can declare his/her skills via a group of HABTM Checkboxes available on that view with the form...
What I want to do is to have a view where I have Links based on the different skills, for example: "policemen", "doctors", "musicians" etc. And these links should point to other views where I can show to the visitor a list of only the users that belong to the specific category they clicked on.
My users/skills models (association part) look like this:
#User Model
class User < ActiveRecord::Base
has_and_belongs_to_many :skills
#Skill Model
class Skill < ActiveRecord::Base
has_and_belongs_to_many :users
And (if it's helpful) my HABTM checkboxes look like this:
<p> What Skills do you have?
<% for skill in Skill.find(:all) %>
<div>
<%= check_box_tag "user[skill_ids][]", skill.id, #user.skills.include?(skill) %>
<%= skill.name %>
</div>
<% end %>
</p>
Let's say the skills we have are: "policeman, doctor, musician" for example... How can I create links in a view wich point to the group of users that have X skill and then with what code could I render some views that display lists with only the users that belong to X skill category?
I bet the solution is really simple... But I'm missing something obvious, maybe. Could you point me in the right direction?
Thanks!
In config/routes.rb:
resources :skills
Generate a SkillsController with rails g controller skills and put there:
def index
#skills = Skill.all
end
def show
#skill = Skill.find(params[:id])
end
Then your views:
#app/views/skills/index.html.erb
<ul>
<% #skills.each do |skill| %>
<li><%= link_to skill.name, skill_path(skill) %></li>
<% end %>
</ul>
and
#app/views/skills/show.html.erb
<h1>Users who have the <%= #skill.name %> skill</h1>
<ul>
<% #skill.users.each do |user| %>
<li><%= user.full_name %></li>
<% end %>
</ul>
First of all dont use the has_and_belongs_to_many. Here is a link to RoR Guides showing how you are supposed to do the has_many :through assosiation. http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association
Secondly if you want to show your user that have 'x' skill it just the skills#show action.
def show
#skill = Skill.find params[:id]
#users = #skill.users
end
And on your links to view this would be something like skill_path(skill)
Related
I'm new to ruby on rails and I'm building a wiki app where the navigation is to be sorted by categories. Each article, or page, can belong to a category, but a category can also be a sub-category of another category. An administrator will be able to create new categories or sub-categories calling for a dynamic approach to generating a list of categories for the menu. I'm trying to figure out how to display a list of all parent categories and all of their children and grandchildren categories where the menu would look something like this:
1. Parent1
1.a Child1
1.b Child2
2. Parent2
2.a Child1
2.a.1 Grandchild1
I currently have some nested loops in my view which kind of work, but it's not dynamic since it will only show the first two generations, and I would have to repeat the code to show more.
Model:
class Category < ApplicationRecord
has_many :sub_categories, class_name: "Category", foreign_key: "category_id"
belongs_to :category, class_name: "Category", optional: true
end
Controller:
class CategoriesController < ApplicationController
def index
#sorted_categories = Category.order(:sort_number).where("category_id IS NULL")
#sub_categories = Category.order(:sort_number).where("category_id IS NOT NULL")
end
end
View:
<% if #categories.nil? %>
<h3>There are currently no categories.</h3>
<% else %>
<ul>
<% #sorted_categories.each do |c| %>
<li><%= c.name %><%= link_to 'Move Up', categories_move_up_path(c) %> Sort:<%= c.sort_number %></li>
<% #sub_categories.each do |s| %>
<% if s.category_id == c.id %>
<ul>
<li>
<%= s.name %><%= link_to 'Move Up', categories_move_up_path(s) %> Sort:<%= s.sort_number %>
</li>
</ul>
<% end %>
<% end %>
<% end %>
</ul>
<% end %>
Any advice would be greatly appreciated, thanks!
Have a look at the acts_as_list gem, it does exactly what you want.
It will define a parent_id column, and each object will be a child of a parent, so that you can create infinite tree of categories ans sub-categories.
It also provides the methods to move objects up and down.
I have two models here, Groups and Posts. Posts belong to group and groups have many posts. Here is my issue. I have an index page of groups. I'm trying to have a sidebar display a list of latest posts. I am unable to link to the posts because of the nested routes (I can't get the correct parameter for the group because this is all appearing on the group index page). Here is how I first tried to do it:
<% #latest_posts.each do |post| %>
<li><%= link_to post.title, group_post_path(#group, post) %></li>
<li><%= post.group.title %></li>
<% end %>
I've already looped through the list of groups on this same view, though:
<% #groups.each do |group| %>
<div class="table-cell">
<%= link_to group.title, group %>
</div>
<div class="table-cell">
<%= group.description.truncate(70) %>
</div>
<% end %>
So in my groups controller, I can't just make a #group instance variable to place into the group_post_path params. Here's my controller:
def index
#latest_posts = Post.order('created_at DESC').limit(20)
#groups = Group.order('created_at DESC').page(params[:page]).per(25)
end
So I have two problems. My main one is that I can't link to the post. I thought this would work, but no to that one also (I have friendly id set up, so I need to link to the group name instead of the id here.)
<%= link_to post.title, group_post_path(post.group_id, post) %>
But any attribute from the parent isn't available.
<%= post.group.title %>
produces
undefined method `title' for nil:NilClass
The same goes for trying it in the params.
<%= link_to post.title, group_post_path(post.group.title, post) %>
My models:
class Post < ApplicationRecord
belongs_to :group
class Group < ApplicationRecord
has_many :posts
How can I get at least access to the parent attributes?
I use Devise gem for authentication.
In database I have users table and posts table in my database schema (and Post controller).
In post controller I want to find all posts assigned to specific user. I have user_id in posts table.
How to get all user's posts or how to check if specific post is assigned for SIGNED IN user.
I thought about something like this (of course is only pseudocode:
current_user.id == Post.where(params:[post_id]).user_id
So how to get current user id in Devise and how to check the current user id is the same like eg. user_id assigned to viewing post (I want to add 'edit' function when current user is post owner) and how to find all post which current user is owner.
Associations
Firstly, your user_id column in your posts table is what's known as a foreign_key
Foreign keys are used in relational database systems to give you the ability to call associative data from a single record. Simply, it means that you'll be able to use the ActiveRecord associations to call the data you require, rather than having to call it individually:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :posts
end
#app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
end
This will give you the ability to use the following call:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
#posts = current_user.posts
end
end
You'll be best served looking up the has_many association:
Fix
In regards to showing your posts for your users, you need to be sure that you have the correct "flow" set up. What I mean is you need some condition to know whether your user is signed in & that #posts is set:
#app/views/posts/index.html.erb
<% if #posts.present? %>
<% #posts.each do |post| %>
<%= post.title %>
<% end %>
<% end %>
Maybe this is the first time you use Devise. You can access current_user inside controllers or views. I imagine you could do something like this
In controller (posts_controller.rb):
#posts = current_user.posts
In view (posts/show.html.erb, I guess):
if current_user.id = #post.current_user
#render something here
end
Get all post which current user is owner.
#posts = Post.where(:user_id => current_user.id)
and on your view
<%-# commented : checking if #posts is empty -%>
<% if #posts.empty? %>
<span>Sorry, post is empty </span>
<% else %>
<%= #posts.each do |p| %>
<% if p.user_id == current_user.id %>
<% link_to "edit", edit_path(p) %>
<% end %>
<% end %>
<% end %>
There are many ways you could get current_user posts. I'll go the long way.
we need
an action
an action view and a partial
a route
a link_to
* action *
def my_posts
#posts = current_user.posts.all.order(created_at: 'DESC')
end
* view *
my_posts.html.erb
<% if #posts.present? %>
<%= render 'posts' posts: #posts %>
<% else %>
<h1>You don't have any posts yet! create one</h1>
<% end %>
_posts.html.erb
<%posts.each do |post| %>
<%= post.title %>
<% end %>
index.html.erb
<%= render 'posts' posts: #posts %>
route
get 'post' => 'posts#my_posts', as: :my_posts
link_to
<%= link_to 'My posts', my_posts_path %>
I may be late but someone can find it useful :)
So I have two models, Users that belong_to Organization (which has_many users). I'm using a partial to display all the users that belong to any one particular organization, and this is working fine if I output just the name (it correctly names all the users). However when I change the partial code to provide link_to user.name, the returned links are all links to the parent Organization rather than the individual child objects. What am I doing wrong?
Relevant code:
Organizations Controller
def show
#organization = Organization.find(params[:id])
#users_index = User.joins(:organization).where(organizations: {id: #organization.id})
end
Organization.show.html.erb
<% provide(:title, #organization.organization_name) %>
<h1><%= #organization.organization_name %></h1>
<h2>Your Organization's Users:</h2>
<%= render partial: "users_index", collection: #users_index %>
_users_index.html.erb code:
<p class="users"><%= link_to users_index.name %></p>
If you set up your relationship properly then you can use:
#users_index = #organization.users
And then you need to loop through #users_index and pass that to your partial.
#users_index.each do |user|
<%= render "users_index", :user => user %>
end
And in your partial, change to:
<p class="users"><%= link_to user.name, user %></p>
link_to
I think the core of the issue, as alluded to in the other answer, is your link_to:
<%= link_to users_index.name %>
The link_to helper method basically works like this:
<%= link_to "Your Link Text", link_path %>
I don't see how your application will be able to load the correct link path without your definition, irrespective of whether you added it to the helper or not.
I presume that your rendered link will point to "#", not the "parent object" as you alluded.
--
Fix
I'd do this:
#app/views/organization/show.html.erb
<%= render partial: "users_index", collection: #users_index, as: :user %>
#app/views/organization/_users_index.html.erb
<p class="users"><%= link_to user.name, user %></p>
This should set the correct link_to helper method for you
--
Models
Further, I would also address the associations in your models
You're currently calling users in the most inefficient way. ActiveRecord associations work to remedy this:
#app/models/user.rb
Class User < ActiveRecord::Base
belongs_to :organization
end
#app/models/organization.rb
Class Organization < ActiveRecord::Base
has_many :users
end
This will allow you to call the following:
#app/controllers/organizations_controller.rb
Class OrganizationsController < ApplicationController
def show
#organization = Organization.find params[:id]
#users_index = #organization.users
end
end
I have read so much about Rails in the past week in the process of trying to learn it. The problem is when I need something I find it difficult to recall where I read it! ha ha
I have two models: Guest and Booking where Guests has_many Bookings. Therefore the Booking model has a guest_id field included.
I would like to retrieve all the booking data and the guest data and display in a view as one object. I know I have seen a simple solution to this (in the Rails doc I think) that does just this.
At the moment I'm doing the following in my BookingsController:
#bookings = Booking.all
and in my associated view I have:
<% #bookings.each do |booking| %>
<p><%= booking.id %></p>
<p><%= booking.email %></p> //this does not work as email is in guests table!!!
<% end %>
but how can I get the linked Guest table included too?
If your booking belongs to guest
class Booking < ActiveRecord::Base
belongs_to :guest
...
end
you can first include guest to avoid n+1 queries
#bookings = Booking.includes(:guest).all
and then in view, traverse the association
<% #bookings.each do |booking| %>
<p><%= booking.id %></p>
<p><%= booking.guest.email %></p>
<% end %>
In your bookings controller:
#bookings = Booking.includes(:guest).all