Access parent attributes through child - ruby-on-rails

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?

Related

Rails - List a all items method in controller

I need to list all my lawns in one page and then all my bookings in another page. I am writing a method in my controller to list my all items in my database but the problem is either it displays 1 in the view or it produces an inheritance error(in the view) . What I have so far is a lawn that has_many bookings (should actually be has one booking) and a booking which belongs to a lawn and everything is controlled through Activeadmin. The error I get is
undefined method `description' for
Lawn::ActiveRecord_Relation:0x007f4451b00a58> I have modified the error a little bit so it can show over here.
Here is my controller code. A lawn has a title and a description so I am not sure why I get the error. I have put 2 different methods for lawn and booking but they are both not working. Here is my controller.
def display_lawns
#lawn = Lawn.all
end
def display_status
#lawn = Lawn.where("selected = ?", "true")
#bookings = #lawn.booking
end
And here is my view file which does not seem to work with the Lawn.all I also have a similar view file for the bookings with a few changes.
<h2><%= #lawn.description %></h2>
<ul>
<% #lawn.bookings.each do |booking| %>
<li>
<%= booking.description %>
<%= button_to "Select", update_booking_path(booking_id: booking), remote: true %>
</li>
<% end %>
</ul>
A couple of hints.
Instead of
#lawn = Lawn.where("selected = ?", "true")
Is better to add a scope in your model.
#lawn is an array of objects, so use plural.
def display_lawns
#lawns = Lawn.all
end
def display_status
#lawns = Lawn.all.where("selected = ?", "true")
end
#lawns is an array, so you can't use #lawn.description
#lawn.first.description works if you need the first item of the array
<h2><%= #lawns.first.description %></h2>
<ul>
<% #lawns.each do |lawn| %>
<li>
<%= lawn.description %>
<%= button_to "Select", update_booking_path(booking_id: lawn.booking), remote: true %>
</li>
<% end %>
</ul>
Lawn.all and Lawn.where(...) return an ActiveRecord::Relation, consisting of multiple lawns.
In your view, you try to display a lawn's description via #lawn.description, but #lawn is not a single lawn object, but a collection of lawn objects, and the collection does not have a description.
Either only show one lawn object, or loop over all the objects in #lawn (and rename it to #lawns).

Devise - how to show user's post

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 :)

Why does link_to when used in a partial return a link to the parent object rather than the actual object?

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

Rails views based on HABTM Category

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)

Cannot manage associations in Ruby on Rails

I have a Post model which is used to store content posted by guest users, and that content is managed by an Admin user. The admin has the rights to block or unblock a particular post.
What I want to do is this:
Display all unblocked Posts to the Guest Users.
Display all Posts to the admin user.
For the first requirement, I have a model BlockedPost which has a polymorphic association with Post model. The post that will be blocked by the admin will be maintained in the BlockedPost model.
For the second requirement I have to give admin the right to block or unblock any particular content. So in my posts/index.html.erb I have done this
<% #posts.each do |post| %>
<% post.content %>
<% if post.post_blocked? %>
<td><%= link_to 'Unblock', blocked_post_path(content.id),:method => :delete%></td>
<% else %>
<td><%= link_to 'Block', create_blocked_post_path(content.id) %></td>
<% end %>
<% end %>
The post_blocked? method above is defined in the Post model:
class Post < ActiveRecord::Base
def post_blocked?
!self.blocked_posts.nil?
end
end
This works but the problem is every time the post_blocked? method is called it makes a database call.
Is there any way to stop this behavior and get the status of all posts in one database call itself?
hmm... i think you should change your models a little, because they are unconfortable a bit and there isnt any fast way to get your posts from DB,
delete BlockedPost model
and add a column to Post model (in migration)
t.boolean :blocked, :default => true
I'd do it like this:
#blocked_posts = Post.where( :blocked => false)
#unblocked_posts = Post.where( :blocked => true )
or prepare scopes in your Post model
and then in your view just display 2 lists
<% #unblocked_posts.each do |upost| %>
<%= upost.content %>
<%= link_to 'Block that post', ... %>
<% end %>
<% #blocked_posts.each do |bpost| %>
<%= bpost.content %>
<%= link_to 'Unblock', ... %>
<% end %>

Resources