Rails has_many association issue in controller - ruby-on-rails

I have a company model designed with the devise , and when the company is logged in the company can create the event so that the company has many events and events belong to company the events controller is given as
class EventsController < ApplicationController
before_action :company_signed_in?
def index
#events = Event.all
end
def new
#event = current_company.events.build
end
def create
#event = current_company.events.build(event_params)
if #event.save
flash[:success] = "Profile saved"
redirect_to company_events_path(current_company)
else
flash[:error] = "Error"
render :new
end
end
def show
#event = current_company.events.where(id: params[:id]).first
end
private
def event_params
params.require(:event).permit(:name, :company_id, :category_id, :event_date, :event_info, :place, :event_avatar)
end
end
and the company model has
has_many :events
and the event model has
belongs_to :company
the new view of the event has
<%= form_for [current_company, #event] do |f| %>
<%= f.text_field :name %>
<% end %>
and the show view has
<%= #event.name %>
my routes are
resources :companies do
resource :company_profile, :events
end
now what i want to do is the current company can create an event and when the event is created it should be redirected to the show page of the event just produced
i need to create an event so that i can get the url like companies/3/events/3 this type of url
issue is when i am going to the show action i am getting undefined method 'name' Please help ! and in the log i have
Started GET "/companies/3/events" for 127.0.0.1 at 2015-07-30 16:41:54 +0530
Processing by EventsController#show as HTML
Parameters: {"company_id"=>"3"}
Company Load (0.3ms) SELECT `companies`.* FROM `companies` WHERE `companies`.`id` = 3 ORDER BY `companies`.`id` ASC LIMIT 1
CompanyProfile Load (0.3ms) SELECT `company_profiles`.* FROM `company_profiles` WHERE `company_profiles`.`company_id` = 3 LIMIT 1
Event Load (0.3ms) SELECT `events`.* FROM `events` WHERE `events`.`company_id` = 3 AND `events`.`id` IS NULL ORDER BY `events`.`id` ASC LIMIT 1
Rendered events/show.html.erb within layouts/application (12.5ms)
Completed 500 Internal Server Error in 32ms (ActiveRecord: 0.8ms)
ActionView::Template::Error (undefined method `name' for nil:NilClass):
1:
2: <label>Name : </label>
3: <%= #event.name %>
4: <%= #event.event_date %></br></br>
5: <label>Age : </label>
6: <%= #event.place %></br></br>
app/views/events/show.html.erb:3:in `_app_views_events_show_html_erb__541678279__634038278'

you are not passing id of event to the show action. only company_id is passed as shown in parameters
Parameters: {"company_id"=>"3"}
so when it queries in the event with id NULL it didnt find any event and hence null.name is crashing
Either pass id of event to the show action. or for testing you should do this
def show
#event = current_company.events.first
end

You should try the below method and see if it works:
def show
#event = Event.find(params[:id])
end

Related

Rails foreign key assignment failing

I am creating a simple workflow where, after signing up, a publisher can create a newsletter. This newsletter needs three pieces of information: title, description, and publisher_id (i.e. the creator). My question is two-fold:
What is the 'correct' way to set the publisher_id, given that newsletters will have posts nested inside them and Rails recommends not nesting resources more than one level deep (i.e. I shouldn't nest newsletter inside publisher)?
If I am generally approaching it the correct way (see below), how am I supposed to pass the publisher_id and what am I doing wrong?
The workflow is as follows:
Create publisher and set session[:id] to #publisher.id.
Redirect to the newsletter new view.
Upon creating a newsletter, set the newsletter's publisher_id to the session[:id].
Upon navigating to to '/newsletters/new', I'm seeing the following error:
Started GET "/newsletters/new" for ::1 at 2020-05-04 15:53:22 -0700
Processing by NewslettersController#new as HTML
"<ActionController::Parameters {\"controller\"=>\"newsletters\", \"action\"=>\"new\"} permitted: false>"
Rendering newsletters/new.html.erb within layouts/application
Rendered newsletters/new.html.erb within layouts/application (Duration: 2.3ms | Allocations: 738)
And upon submitting 'Create Newsletter', I'm seeing the following error:
ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError):
app/controllers/newsletters_controller.rb:21:in `create'
Started POST "/newsletters" for ::1 at 2020-05-04 15:58:34 -0700
(0.0ms) SELECT sqlite_version(*)
Processing by NewslettersController#create as JS
Parameters: {"authenticity_token"=>"XXX", "newsletter"=>{"title"=>"Newsletter 1", "description"=>"Description content"}, "commit"=>"Create Newsletter"}
Completed 500 Internal Server Error in 11ms (ActiveRecord: 1.0ms | Allocations: 7085)
publishers_controller.rb
class PublishersController < ApplicationController
def create
#publisher = Publisher.new(publisher_params)
if #publisher.save!
session[:id] = #publisher.id
redirect_to new_newsletter_path
else
render 'new'
end
end
private
def publisher_params
params.require(:publisher).permit(:email, :password)
end
end
newsletters_controller.rb
class NewslettersController < ApplicationController
def new
#newsletter = Newsletter.new
end
def create
#newsletter = Newsletter.new(newsletter_params)
if #newsletter.save!
redirect_to #newsletter
else
render 'new'
end
end
private
def newsletter_params
params.require(:newsletter).permit(:title, :description).merge(publisher_id: session[:id])
end
end
/newsletters/new.html.erb
<%= form_with model: #newsletter, url: newsletters_path do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :description %><br>
<%= form.text_area :description %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
You have misunderstood what the rails guides meant by "nesting resources more than one level deep" - whats really meant is that this is OK:
/publishers/1/newsletters/new
Which is one level of nesting and the nesting provides very useful contextual information. While these are kind of fishy:
/publishers/1/newsletters/2
/publishers/1/newsletters/3/replies/new
In both cases we have two levels of nesting should be able to reach the nested resource without going though publishers.
/newsletters/2
/newsletters/3/replies/new
Also if you want to add values from the session or somewhere else then the params hash when creating a record use a block or create the record off the association instead:
class NewslettersController < ApplicationController
def create
#newsletter = Newsletter.new(newsletter_params) do |newletter|
newsletter.publisher = current_publisher
end
# or
# #newsletter = current_publisher.newsletters(newsletter_params)
# save! will raise an exception if the record is not valid
# that is NOT what you want here
if #newsletter.save
redirect_to #newsletter
else
render 'new'
end
end
end
This makes it much more apparent what is coming from where.

Rails, updating records for an invitation system

I want to allow users to accept invitations, the accept tag is in the invite model itself (so I need to update the table). So far nothing occurs when the user clicks the accept button
View
<% #invites.where(user_id: current_user.id).find_each do |invite| %>
...
<%= button_to "Accept", accept_invite_invites_path(invite), method: :put %>
end
Routes
resources :invites do
collection do
get 'accept_invite'
end
end
Controller
def accept_invite
#invite = Invite.find(params[:id])
#invite.accept
end
def decline_invite
#invite = Invite.find(params[:id])
#invite.decline
end
def set_invites
#invite = #story.invites.find(params[:id])
end
def new
#invite = #story.invites.new
end
I get "undefined method `invites' for nil:NilClass" if I keep :update as a part of set_invites, removing update allows my code to run, but no changes to the database is made.
Model
def accept
accept = true
save
end
def decline
accept = false
save
end
Console
Processing by InvitesController#update as
Parameters: {"authenticity_token"=>"BDle9fqXHT9ZFctMbO4RvxfPuTQXe2Nq+b6/T29B3xjpYdtMozVUFLiRlaQFtuYzMrBceTQn8OtfGjJTe4wa/Q==", "id"=>"accept_invite"}
User Load (1.7ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 ORDER BY `users`.`id` ASC LIMIT 1
No template found for InvitesController#update, rendering head :no_content
Completed 204 No Content in 85ms (ActiveRecord: 1.7ms)
It's weird because the database is selecting from the user table rather than updating the invites table
So what is the problem? Is the route faulty? My set_invites method?
So what is the problem? Is the route faulty? My set_invites method?
Yes,your route is faulty. As I can see you declared your route on a collection, but you need it on a member. And also you should change it to put.
resources :invites do
member do
put 'accept_invite'
end
end

Just created Users with Devise, want to give users their own set of objects in rails

I am working on a rails application that has these classes..
many STOCKS has..
=> many TIME_DELTAS
Now I just created a branch and added devise to the application. Now, I want each user to be able to have their own stock objects, not a shared database of them but user specific has their own set of stocks in their own private session.
Would I be correct in assuming to do this I would need to make the stocks a nested class of user so each user has their own stocks? Is their a guide to doing this easily? Thanks!!
Index
def index
if current_user
#stocks = current_user.stocks
else
redirect_to new_user_session_path, notice: 'You are not logged in.'
end
end
Create
def create
# XXX Add columns for delta and current standing when we get there
# they can intiate to nil
# params['stock'][:user] = current_user
#stock = Stock.new(stock_params)
#stock.user = current_user
if #stock.save
redirect_to #stock
else
render 'new'
end
end
Update
def update
#stock = find_stock
if #stock.update(stock_params)
redirect_to #stock
else
render 'edit'
end
end
Serverlog
Started POST "/stocks" for 127.0.0.1 at 2014-05-04 15:25:15 -0700
Processing by StocksController#create as HTML Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"AvtGUf+gPXnpMHNASQK74G+f97Ho4YxkUDEfl+lhZQg=",
"stock"=>{"name"=>"Google", "hashtag"=>"goog"}, "user"=>"2",
"commit"=>"Create Stock"} User Load (0.9ms) SELECT "users".* FROM
"users" WHERE "users"."id" = 2 ORDER BY "users"."id" ASC LIMIT 1
(0.0ms) begin transaction Stock Exists (0.1ms) SELECT 1 AS one
FROM "stocks" WHERE "stocks"."hashtag" = 'goog' LIMIT 1 Stock Exists
(0.1ms) SELECT 1 AS one FROM "stocks" WHERE "stocks"."name" =
'Google' LIMIT 1 (0.0ms) rollback transaction Completed 500
Internal Server Error in 6ms
NoMethodError (undefined method attributes' for nil:NilClass):
app/controllers/stocks_controller.rb:21:increate'
Rendered
/Users/nathanielmots/.gems/ruby/2.1.0/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_source.erb
(0.6ms) Rendered
/Users/nathanielmots/.gems/ruby/2.1.0/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_trace.erb
(1.2ms) Rendered
/Users/nathanielmots/.gems/ruby/2.1.0/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
(1.1ms) Rendered
/Users/nathanielmots/.gems/ruby/2.1.0/gems/actionpack-4.0.3/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (13.5ms)
Use Active Record Association.
class User < ActiveRecord::Base
has_many :stocks
end
class Stock < ActiveRecord::Base
belongs_to :User
end
In order to setup 1-M relationship between User and Stock model, you would need to define the association as suggested below:
class User < ActiveRecord::Base
has_many :stocks
## ...
end
class Stock < ActiveRecord::Base
belongs_to :user
## ...
end
After this create a foreign_key user_id in stocks table as below:
Generate a migration for adding user_id reference to stocks table by running:
rails generate migration AddUserRefToStocks user:references
After this run rake db:migrate
NOTE:
make the stocks a nested class of user so each user has their own stocks?
There is no such thing as nested class in Ruby. What you mean probably is how to setup association between User and Stock classes.
UPDATE
Change your new and create actions in StocksController as below:
def new
#stock = current_user.stocks.build
end
def create
#stock = Stock.new(stock_params)
if #stock.save
redirect_to #stock, notice: 'Stock was successfully created.'
else
render 'new'
end
end
Also, add a hidden field (within form_for) in the new view of stocks as below:
<%= f.hidden_field :user_id %>
NOTE: Make sure that you permit the field user_id in stock_params method.

Can't make conroller working with params hash

I have has_many association and want get Users Websites and from console user.websites gives me list of all websites, but when I try in controller:
def index
#websites = User.find(params[:user_id]).websites
end
Gives me error:EDIT
Rendered C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.2/lib/action_dispatch/middleware/templates/rescues/_trace.erb (3.0ms)
Rendered C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.2/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.0ms)
Rendered C:/Ruby193/lib/ruby/gems/1.9.1/gems/actionpack-3.2.2/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (99.0ms)
←[1m←[36mUser Load (2.0ms)←[0m ←[1mSELECT `users`.* FROM `users` WHERE `users`.`id` =67 LIMIT 1←[0m
Completed 500 Internal Server Error in 2ms
ActiveRecord::RecordNotFound (Couldn't find User without an ID):
app/controllers/websites_controller.rb:10:in `index'
but I am logged in and do have user with id =67:
User.find(67)
=> #<User id: 67, first_name: "admin", ...
In my view:
<% #websites.each do |website| %>
<%= website.name %>
<%= website.url %>
<p> <%= website.category %>
<%= website.language %>
<%end%>
EDIT.Tried to inspect params[:user_id] in index view, and this didn't show me anyhing:
<%= params[:user_id]%>
Why I'm getting errors ?
Where are you getting the params[:user_id] from?
Have you tried:
def index
#websites = User.find(params[:id]).websites
end
You need to explain how you are finding the user.
You said that you are logged in, so do you have a current_user?
def index
#websites = current_user.websites
end
or do it in parts:
def index
#user = #find the user
#websites = #user.websites
end

RoR, params not being passed to the controller for a :remote link_to

Ok ill be honest, i haven't spent much time looking for a solution yet seeing as how my son is keeping my attention running around. Either way I would like to ask a question for something that seems pretty simple but has stumped me thus far.
So to keep it simple lets say I have Users(w/model) and Home controllers, Home is the root route.
In the root directory I want to be able to see all posts made by the User using ajax to update a partial on the home page with the list of posts.
In the users controller I have a def called userposts with this in it
def userposts
#user = User.find_by_id(params[:id])
#userposts = #user.posts.all(:order => "created_at DESC")
respond_to do |format|
format.js { #userposts}
end
end
And in my view I have
<p id="aboutuser">
<% if #user.about? %>
<%= " " + #user.id.to_s %>
<% else %>
User has not yet filled this out.
<% end %>
</p>
<h3 id="authpostlink">
<%= link_to "List of all posts", user_userposts_path(#user.id), :id => #user.id, :remote => true %>
</h3>
my errors are as follows
Started GET "/users/2/userposts" for 127.0.0.1 at Sun Jan 15 13:36:23
-0600 2012 Processing by UsersController#userposts as JS Parameters: {"user_id"=>"2"} User Load (0.1ms) SELECT "users".*
FROM "users" WHERE "users"."id" IS NULL LIMIT 1 Completed 500 Internal
Server Error in 1ms
NoMethodError (undefined method posts' for nil:NilClass):
app/controllers/users_controller.rb:27:inuserposts'
Rendered
/home/n0de/.rvm/gems/ree-1.8.7-2011.03/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/_trace.erb
(0.8ms) Rendered
/home/n0de/.rvm/gems/ree-1.8.7-2011.03/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
(0.8ms) Rendered
/home/n0de/.rvm/gems/ree-1.8.7-2011.03/gems/actionpack-3.1.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (3.2ms)
I do realize i did not post the _show.js.erb file that calls the action to update the div but according to the error messages it doesn't seem the process has gotten that far.
Assuming you have the following:
# /app/models/user.rb
class User < ActiveRecord::Base
has_many :posts
end
# /app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
end
I would add a nested resource in your routes file:
#/config/routes.rb
resources :users do
resources: posts
end
You get a bunch of great "_path" methods for free (run $ rake routes from your console to see them all), and it gives you access to URLs such as /users/123/posts. This request will go to the index method of your PostsController and will automatically include :user_id => 123 in the params hash. You can then do the following:
# In your view:
<%= link_to "List of all posts", user_posts_path(#user), :remote => true %>
<div id="posts"></div>
# /app/controllers/posts_controller.rb
class PostsController < ApplicationController
respond_to :js # allows for AJAX requests
def index
if params[:user_id].present? # Do this if using the nested resource
#user = User.find(params[:user_id])
#posts = #user.posts.order('posts.created_at DESC')
else # Otherwise, treat it like a normal request
#posts = Post.all
end
respond_with #posts
end
end
Because the your request is sent remotely, you need a corresponding "js" version of your index view (note the file name below and see this Railscast for more explanation):
# /app/views/posts/index.js.erb
$('#posts').html("<%= escape_javascript(render(#posts)) %>");
This will render out the posts into that <div id="posts"> tag. (You'll probably need a "_post.html.erb" partial in /app/views/posts/" as well.)
However, having said all this, are you sure you need to do this via AJAX? You could simply preload all the posts in the UsersController#show method, initially hide the list using CSS, and then add a jQuery toggle() method on that link. Anyway, hope this makes sense and is helpful.

Resources