rails model associations recorded in controller - ruby-on-rails

I have an application with 3 models user company and post.
I'm having trouble with figuring out the logic
A user can have many companies and a company can have many posts.
here are my models
class user < ActiveRecord::Base
has_many :companies
end
class company < ActiveRecord::Base
belongs_to :user
has_many :posts
end
class post < ActiveRecord::Base
belongs_to :company
end
Note: company has user_id, post has company_id in table
how do I make sure when creating a post the company_id is automatically recorded
extra information: for routes it will be resources :jobs and resources :companies
--update--
post controller
def new
Post.new(post_params)
end
def create
Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
routes
resources :companies
resources :posts

I think I would probably nest posts within companies, so you would have available to you the company_id in the parameters.
Note your path names will change if you do this.
Routes.rb
resources :companies do
resources :posts
end
posts_controller.rb
def create
#company = Company.find(params[:company_id])
#post = #company.posts.build(post_params)
...
end
And since you will want to find the company on each of these actions in the controller, you can refactor it a bit.
class PostsController
before_action :set_company
def index
#post = #company.posts
end
def create
#post = #company.posts.build(post_params)
...
end
...
...
private
def set_company
#company = Company.find(params[:company_id])
end
end

2 options come to mind.
You can create a hidden company_id field in your posts#new view, so it would be sent automatically along with your params and hence be set in the model accordingly (provided that you permit it). But in that case you'll need to populate that field in the controller when creating the #post. Just like this:
#post = Post.new(company_id: some_company_id)
Use nested resources.First of all change your routes to this:
resources :companies do
resoures :posts
end
That way when you look at the rake routes output you'll see the :company_id param being set in the request url. So when you go on creating a post, you can do #post.company_id = params[:company_id] and you're done.

Related

With Ruby on Rails what's the best way to display data from a form field on a show page from another Ruby class?

I'm still somewhat new to Ruby and am having trouble displaying data on the show page from another class. I have two classes, Company and Job. On the Job show page I would like to display the Company's name, website and description from the Company form fields that created/posted the job when a job applicant views the respective job.
Was receiving an error when tinkering with the Job show controller action. Not entirely sure if the company is not being assigned an id when being created or if there's an issue with the show action login in the controller or a model association error on my end. Any help and explanation to resolve this issue is greatly appreciated.
Screenshot for Error Received on Job Show Page
Models
class Company < ApplicationRecord
has_many :jobs
has_many :job_applications, through: :jobs
class Job < ApplicationRecord
belongs_to :user
belongs_to :company, optional: true
has_many :job_applications, dependent: :destroy
class JobApplication < ApplicationRecord
belongs_to :user
belongs_to :job
Controllers
class CompaniesController < ApplicationController
private
# Use callbacks to share common setup or constraints between actions.
def set_company
#company = Company.find(params[:id])
# #company = self.create_company
end
# Only allow a list of trusted parameters through.
def company_params
params.require(:company).permit(:name, :website, :about, :user_id, :avatar)
end
class JobsController < ApplicationController
# GET /jobs/1 or /jobs/1.json
def show
#company = Company.find(params[:user_id])
# #company = Company.all
# #job = Job.find(params[:id])
end
Routes
resources :companies
resources :jobs
resources :jobs do
resources :job_applications
end
Job Show Page
<%= #company.name %>
<%= #company.website %>
<%= #company.about %>
I believe the problem lies in your show method in the JobsController.
It should look something like this:
class JobsController < ApplicationController
# GET /jobs/1 or /jobs/1.json
def show
#job = Job.find(params[:id])
#company = #job.company
end
This might throw some errors since you have optional: true in your relation. Also, I didn't care of n+1 queries since it's just a record, but this could be improved to be only 1 SQL query to the database.

How to save data from a new object in a nested resource in rails?

I am looking to create a new record within a nested resource in rails as according to http://guides.rubyonrails.org/routing.html.
My model is:
class Entry < ApplicationRecord
belongs_to :user
belongs_to :event
class User < ApplicationRecord
has_many :entries, dependent: :destroy
class Event < ApplicationRecord
has_many :entries, dependent: :destroy
And I have declared my route as
Rails.application.routes.draw do
resources :users
resources :events do
resources :entries
end
What is the syntax for the entries controller for me to be able to create an entry on a link like events/2/entries/new. This is what I was trying:
class EntriesController < ApplicationController
def new
#entry = Entry.new
end
def create
#entry = Entry.new(params[:entry])
if #entry.save
redirect_to #user
flash.now[:info] = "Event Created"
else
render '/create'
flash.now[:danger] = "Somthing went wrong"
end
end
def entry_params
params.require(:event_id).permit(:siCard, :course)
end
end
On by new.html.erb I am using
<%= form_for(new_event_entry_path) do |f| %>.
But I cant get it to work as No route matches [POST] "/events/1/entries/new"
Many thanks
The route you've provided in form_for does not accept POSTs. You've provided the route that renders the new page, not the route that accepts new records, which is the create route. For that, you'll want to use event_entries_path(#event) route helper.
With nested resources, the form_for's first argument should be an array: <%= form_for([#event, #entry], .... Rails will intelligently choose the route you need based on whether the #entry is persisted or not.

Cannot find bids from post_id

I'm having trouble finding my bids that are linked to specific posts via the index method. I have successfully linked my bids to posts (i.e. I have a post_id column within my bids table), but cannot seem to 'find' them. I currently get the error 'Couldn't find Bid with 'id'='
Bids controller:
class BidsController < ApplicationController
def index
#bid = Bid.find(params[:post_id])
end
end
View:
<ul>
<% #bid.each do |bid| %>
<li>$<%= bid.price.floor %></li>
<% end %>
</ul>
Models (post and bid):
class Bid < ActiveRecord::Base
belongs_to :post
end
class Post < ActiveRecord::Base
has_many :bids
end
Routes:
Rails.application.routes.draw do
root 'static_pages#home'
get 'add' => 'posts#new'
get 'posts' => 'posts#index'
get '/posts/:id/new_bid' => 'bids#new'
get '/posts/:id/bids' => 'bids#index'
resources :posts
resources :bids
end
Any help is appreciated. Thank you.
In your routes, you have
get '/posts/:id/bids' => 'bids#index'
Therefore, you will have a params[:id] for your controller. Then in your controller, you should use it:
class BidsController < ApplicationController
def index
#bids = Post.find(params[:id]).bids
end
end
You might consider using nested resources in routes:
resources :posts do
resources :bids
end
Then you will automatically have posts/:post_id/bids and you can use parmas[:post_id] in your controller.
Your index action should be doing used where to find all the bids with a particular post_id.
def index
#bid = Bid.where(post_id: params[:post_id])
end
else you can find the post first and then load the bids from the post like so.
def index
#bid = Post.find(params[:post_id]).bids
end
This error is the result of an empty string sent to Model.find(). You may reproduce this error in rails console ( rails c) with Bid.find('').
By the route file you provide, you should use :id instead of :post_id. And because you want all bids that matches the post_id, this should be #bid=Bid.where(post_id: params[:id])

missing required keys: [:like_id]

I can't get a like system working for my Rails discussion forum:
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :comment
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
has_many :likes, through: :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
has_many :likes
end
routes.rb:
resources :posts do
resources :comments do
resources :likes do
put "/create", to: "likes#create"
end
end
end
likes_controller.rb:
class LikesController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = Comment.find(params[:comment_id])
#like = Like.find(params[:like_id])
#user = current_user.id
Like.create(like_id: #like, post_id: #post, comment_id: #comment, user_id: #user)
respond_to do |format|
format.html { redirect_to post_path(#post) }
end
end
end
rake routes:
post_comment_like_create PUT /posts/:post_id/comments/:comment_id/likes/:like_id/create(.:format) likes#create
post_comment_likes GET /posts/:post_id/comments/:comment_id/likes(.:format) likes#index
POST /posts/:post_id/comments/:comment_id/likes(.:format) likes#create
etc
The problem I keep running into is that it's missing like_id:
No route matches {:action=>"create", :comment_id=>"218", :controller=>"likes", :like_id=>nil, :post_id=>"30"} missing required keys: [:like_id]
What am I doing wrong? I assume most of the code is correct, as the only error it's giving me is a missing ID, I just don't understand how or where to fetch that like_id.
EDIT:
This is the action I'm trying to use:
= link_to post_comment_like_create_path(#post, comment, #like)
The issue is partly in your routes, partly in your controller and partly in the view.
By using the line resources :likes, you are creating routes for the 7 CRUD actions automatically. This means you do not need to manually declare a create action in your routes (which should be a POST rather than PUT). I'd suggest reading the Rails Guide on Routing.
In your controller, you are attempting to create an object called #like by finding a Like based on an ID. But you are creating this for the first time, so there is nothing to find.
In your view, you shouldn't be using a link_to for anything that affects the database but rather a button_to and the path you are using is also part of the problem.
Make the following changes:
routes.rb
resources :posts do
resources :comments do
resources :likes
end
end
likes_controller.rb
class LikesController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = Comment.find(params[:comment_id])
#user = current_user.id
Like.create(post_id: #post, comment_id: #comment, user_id: #user)
respond_to do |format|
format.html { redirect_to post_path(#post) }
end
end
end
view
= button_to post_comment_likes_path(#post, comment)
I would suggest you look at the guides around nesting of routes. Nesting this deep can easily become cumbersome.

Rails nested association and restarted numbering

If I have a nested resource like so:
resources :users
resources :posts
end
and a user has_many posts, it is possible to have Rails start numbering based on the parent association in the URL? For example, currently, nesting resources just grabs the ID:
#user.posts.find(params[:id])
This correctly namespaces the posts, only allowing posts from #user... however, is there a way such that the post_id is independent? I.E. I want each user's posts to start at 1, where:
/users/1/posts/1
/users/2/posts/1
Actually refer to two different posts?
It can be quite a bit of work, but basically you can do it with these steps:
Create a migration to add a new attribute to store the specific user-post count. (I used user_post_id)
Override Post's to_param method to use the new value you just created. (It has to be a string.)
to_param is the method that the url and path helpers use.
Create a before_save filter that will actually increment the user_post_id value for each new post.
Change all your controller methods to find on user_post_id
#user = User.find(params[:user_id])
#post = #user.posts.where(:user_post_id => (params[:id])).first
Change all your Views that might not work now
You can see the source here: Custom Nested Resource URL example
Code
migration:
class AddUserPostIdToPosts < ActiveRecord::Migration
def change
add_column :posts, :user_post_id, :integer
end
end
post.rb:
class Post < ActiveRecord::Base
before_save :set_next_user_post_id
belongs_to :user
validates :user_post_id, :uniqueness => {:scope => :user_id}
def to_param
self.user_post_id.to_s
end
private
def set_next_user_post_id
self.user_post_id ||= get_new_user_post_id
end
def get_new_user_post_id
user = self.user
max = user.posts.maximum('user_post_id') || 0
max + 1
end
end
A couple controller methods
posts_controller.rb:
class PostsController < ApplicationController
respond_to :html, :xml
before_filter :find_user
def index
#posts = #user.posts.all
respond_with #posts
end
def show
#post = #user.posts.where(:user_post_id => (params[:id])).first
respond_with [#user, #post]
end
...
end

Resources