Simple learning app with Rails 4 - Course / Enrolment / User Not working - ruby-on-rails

I am trying to build a simple learning app with rails 4.
here are my models:
class User < ActiveRecord::Base
has_many :enrollments
has_many :lectures, through: :enrollments
accepts_nested_attributes_for :enrollments
end
class Enrollment < ActiveRecord::Base
belongs_to :user
belongs_to :lecture
end
class Lecture < ActiveRecord::Base
has_many :enrollments
has_many :users, through: :enrollments
end
And here are my controllers
class EnrollmentsController < ApplicationController
before_action :authenticate_user!
def create
#enrollments = current_user.enrollments.build(enrollment_params)
if #enrollments.save
flash[:success] = "You have successfully enrolled."
redirect_to profile_path(current_user)
else
flash[:danger] = "Please try again."
redirect_to root_path
end
end
private
def enrollment_params
params.require(:enrollment).permit(:user_id, :lecture_id)
end
end
Here are my views:
lectures/index.html.erb
<% #lectures.each do |lecture| %>
<%= image_tag lecture.picture.url(:medium) %>
<p><%= truncate(lecture.description, length: 80) %> </p>
<%= link_to "Enroll Now", {:action=>"create", :controller=>"enrollments"}, :method => :post %>
<% end %>
The problem is that when you click on Enroll Now I have the following error:
ActionController::ParameterMissing in EnrollmentsController#create
param is missing or the value is empty: enrollment
def enrollment_params
params.require(:enrollment).permit(:user_id, :lecture_id)
end
How can i make it work? Need help please

In your lectures/index.html.erb file, you are not passing any data to the controller's action method.
<%= link_to "Enroll Now", {:action=>"create", :controller=>"enrollments"}, :method => :post %>
Might be better served with something a la
<%= link_to "Enroll Now", {:action=>"create", :controller=>"enrollments", :user_id => current_user.id**, :lecture_id => lecture.id}, :method => :post %>
# ** not sure how you snag the current user's id in your app but you'd need it.
Also, take a look at Routing in Rails. There are some super handy helper methods you can use that will allow you to do something like this (this was done quickly and may not be totally accurate but is offered to show you how you can use a route's path helper to clean up the code and make it even more readable):
<%= link_to 'Enroll Now', enrollments_path({enrollment: { user_id: current_user.id, lecture_id: lecture.id }}), :method => :post %>

Related

NoMethodError in Users#show / undefined method `friendships' for #<Profile:0x007ff052f60b68> Rails

I can´t really figure out why I´m getting this error....Earlier today this was working fine, then I did some modifications that I clearly lost track off, and now when I start up my App I always get this error when I try logging in as a user.
NoMethodError in Users#show
undefined method `friendships' for #<Profile:0x007ff052f60b68>
I have 3 Users in my App and they do all have Profiles.
On current_user Profile page the user is able to see his friends and click on their names to see their profile.
Can anyone help me with this?
TIA Dadi
In views/users/show.html.erb
<h4> <%= current_user.profile.name%> Friends</h4>
<ul>
<% #user.friendships.each do |friendship| %>
<li>
<%= link_to user_profile_path(user), :method => :get do %>
<%= friendship.friend.profile.name %>
<%#= link_to compare_friends_path(#user), :method => :get do %>
<%#= friendship.friend.profile.name %>
(<%= link_to "remove friend", friendship, :method => :delete %>)
</li>
<% end %>
<% end %>
</ul>
In users_controller.rb
def show
#user = User.find(params[:id]).profile
end
In user.rb model
has_many :friendships
has_many :friends, through: :friendships
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
has_many :inverse_friends, through: :inverse_friendships, :source => :user
has_one :profile
In profiles_controller.rb
def show
#user = User.find(params[:user_id])
##profile = #user.profile
end
In profile.rb model
class Profile < ActiveRecord::Base
belongs_to :user
end
In friendship.rb model
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => 'User'
end
In routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { registrations: 'registrations' }
resources :users do
resource :profile
end
resources :friendships
end
EDITED
in the same view I´m linking to the same route and it works, why is that? I mean this is basically the same link? (see below)
<h3>followers <%= current_user.profile.name%> </h3>
<ul>
<% #user.inverse_friends.each do |user| %>
<%= link_to user_profile_path(user), :method => :get do %>
<li><%= user.profile.name %></li>
<% end%>
<% end %>
</ul>
def show
#user = User.find(params[:id]).profile
end
This seems wrong, as you're assigning User.profile to #user.
This would explain the error undefined method 'friendships' for #<Profile:0x007ff052f60b68> as your User model has has_many :friendships, but Profile doesn't.
Note: Using web_console or better_errors can really help track down problems like this and is well-worth spending some time setting up. You get a Ruby console in your browser on an exception, and just typing #user would have told you this is a Profile instance, and not a User instance.
I did some modifications that I clearly lost track off
Another lesson: Change as little as possible, TEST, change as little as possible, TEST, and keep repeating this. That way, if something breaks you know exactly which changes caused the error. Keep this feedback loop as short as feasible. This is also something where tools such as better_errors really help.
For a more in-depth explanation, see Feedback Loops in Software Development.

'Like/Unlike' button with Rails 4

I'm trying to create a simple Like/unlike button with Rails 4. I tried to do this with socialization gem, but after one day of struggling I gave up and decided to modify M. Hartl's 'foollow' mechanism from Rails Tutorial. Here is what i got so far:
User.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :validatable
has_many :questions
has_many :answers
has_many :likes, foreign_key: "liker_id", dependent: :destroy
has_many :liked_answers, through: :likes, source: :liked, source_type: "Answer"
def like?(answer)
likes.find_by(liked_id: answer.id)
end
def like!(answer)
likes.create!(liked_id: answer.id)
end
def unlike!(answer)
likes.find_by(liked_id: answer.id).destroy
end
end
Answer.rb:
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :user
has_many :likes, foreign_key: "liked_id",
class_name: "Like",
dependent: :destroy
has_many :likers, through: :likes, source: :liker
end
Like.rb:
class Like < ActiveRecord::Base
belongs_to :liker, class_name: "User"
belongs_to :liked, class_name: "Answer"
validates :liker_id, presence: true
validates :liked_id, presence: true
end
likes_controller.rb:
class LikesController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :authenticate_user!
respond_to :html, :js
def create
#answer = Answer.find(params[:like][:liked_id])
current_user.like!(#answer)
respond_with #answer.question
end
def destroy
#answer = Like.find(params[:id]).liked
current_user.unlike!(#answer)
respond_with #answer.question
end
end
_like.html.erb:
<%= form_for(current_user.likes.build(liked_id: #answer.id), remote: true) do |f| %>
<div><%= f.hidden_field :liked_id %></div>
<%= f.submit "Like!", class: "btn btn-large btn-primary" %>
<% end %>
_unlike.html.erb:
<%= form_for(current_user.likes.find_by(liked_id: #answer.id),
html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Unlike.", class: "btn btn-large" %>
<% end %>
routes.rb:
Rails.application.routes.draw do
devise_for :users
scope "/admin" do
resources :users
end
resources :questions do
resources :answers do
get :likes
end
end
resources :likes, only: [:create, :destroy]
root to: 'questions#index'
end
I also have jQuery and jQuery_ujs required in application.js, and relevant js.erb files ("create" and "destroy") in views.
The 'like/unlike' mechanism itself seems to work pretty well - in the console, with my 'like!' and 'unlike!' methods, I'm able to create and destroy "Like" objets with id, liker_id and liked_id.
The problem begins with the button itself.
I can see the "Like!" button next to each answer, but when I click it - I get this error:
ActiveRecord::RecordNotFound in LikesController#create
Couldn't find Answer with 'id'=
The error points on this line in LikesController:
#answer = Answer.find(params[:like][:liked_id])
so I suppose my #answer.id results to be 'nil', but I have no idea where did I make mistake. My first guess would be routes file - I'm still not sure if everything is correct there.
I've spent whole day looking for solution, I also found some similar questions on SO, but none of the answers could help me.
Any ideas would be greatly appreciated.
EDIT: Params from the error
Parameters:
{"utf8"=>"✓",
"like"=>{"liked_id"=>""},
"commit"=>"Like!"}
You're using the hidden field tag wrong. http://api.rubyonrails.org/v4.1.1/classes/ActionView/Helpers/FormHelper.html#method-i-hidden_field shows you need to supply two values into your tag. Change your like ERB file to this:
_like.html.erb:
<%= form_for(current_user.likes.build(liked_id: #answer.id), remote: true) do |f| %>
<div><%= f.hidden_field :liked_id, :value => #answer.id %></div>
<%= f.submit "Like!", class: "btn btn-large btn-primary" %>
<% end %>
and that should get you what you want.

Rails 4 has_many :through w/ check_box_tag - only one side of associate being saved to join table

I'm fairly new to Rails and I've been trying to extend Michael Hartl's tutorial in various ways. One of which is to model user interests using a has_many :through association. I have the following models set up:
class Interest < ActiveRecord::Base
has_many :user_interests, dependent: :destroy
has_many :users, through: :user_interests
end
class User < ActiveRecord::Base
has_many :user_interests, dependent: :destroy
has_many :interests, through: :user_interests
end
class UserInterest < ActiveRecord::Base
belongs_to :user
belongs_to :interest
end
My user_interests controller:
def index
end
def create
#user_interest = current_user.user_interests.build(params[:interest_ids])
if #user_interest.save
redirect_to current_user
flash[:success] = "Interests updated!"
else
render 'index'
end
end
def destroy
#user_interest = UserInterest.find(params[:user_id][:interest_ids])
current_user.user_interests(#user_interest).destroy
end
The view:
<%= form_for(current_user.user_interests.build(params[:interest_ids])) do |f| %>
<%= hidden_field_tag "user[interest_ids][]", nil %>
<% Interest.all.each do |interest| %>
<%= check_box_tag "user[interest_ids][]", interest.id, current_user.interest_ids.include?(interest.id), id: dom_id(interest) %>
<%= label_tag dom_id(interest), interest.activity %><br>
<% end %>
<%= f.submit "Update interests", class: "btn btn-large btn-primary" %>
<% end %>
When I run the app I can select a check box and click the submit button but only the user id is saved in the user_interests table. So it will look like:
id integer user_id interest_id created_at_timestamp updated_at_timestamp
1 2155 2014-04-06 ect... 2014-04-06 ect...
At first I was trying to use the users controller to create the association, but that was causing issues because I didn't have the interests check boxes displayed on the users#edit action, I wanted them to have their own page. What do I need to do to get the interest ids to save to the user_interests table along with the user id?
Please have a try with the following code.
def create
interests = Interest.where(id: params[:user][:interest_ids])
current_user.interests.push(interests)
flash[:success] = "Interests updated!"
redirect_to current_user
end

How to delete a join table association between two models?

I have the following setup of models and controllers:
Models:
class Company < ActiveRecord::Base
has_many :follow_companies, dependent: :destroy
has_many :followers, through: :follow_companies, source: :user
end
#join table
class FollowCompany < ActiveRecord::Base
attr_accessible :company_id
belongs_to :user
belongs_to :company
end
class User < ActiveRecord::Base
#a user can follow many companies
has_many :follow_companies, dependent: :destroy
has_many :followed_companies, through: :follow_companies, source: :company
end
Controllers:
class FollowCompaniesController < ApplicationController
def create
company = Company.find params[:follow_company][:company_id]
current_user.follow_companies.create! company_id:company.id
redirect_to company
end
def destroy
company = Company.find params[:id]
current_user.follow_companies.find_by(company_id: company.id).destroy
redirect_to company
end
end
The join table as well as companies and users is a resource:
resources :users
resources :companies
resources :follow_companies, only: [:create, :destroy]
Now I'd like to have buttons in my frontend for users to UNfollow a company assuming, they already follow that company:
The following view is part of the Company show action and not the FollowCompany show action
View:
<%= follow_company = current_user.follow_companies.find_by_company_id(#company.id) %>
<%= form_for(follow_company, :html => { :method => :delete }) do |f| %>
<%= f.submit "Unfollow", class: "btn pull-right" %>
<% end %>
When browsing to companies/show however, I get an error in the form_for line above:
ActionController::RoutingError at /companies/10
No route matches {:action=>"destroy", :controller=>"follow_companies", :format=>nil, :id=>#<FollowCompany user_id: 2, company_id: 10, created_at: "2013-03-21 23:34:36", updated_at: "2013-03-21 23:34:36">}
Request parameters
{"action"=>"show", "controller"=>"companies", "id"=>"10"}
Why can't rails find the route?
Pretty sure you need to pull :method => :delete out of the html args:
<%= form_for(follow_company, :method => :delete) do |f| %>
Not sure if that's the only problem but that's what caught my eye.
Something like this seems a bit more elegant too (automagically creates a form):
= button_to "Unfollow", follow_company_path(follow_company), :method => 'delete'
An alternative way to achieve this without writing a form is below. If you want you can do this with a single link.
<%= link_to "Unfollow", follow_compony_path(follow_company), :method => :delete %>

rails create custom action

i created a small rails application for learning which has 3 models :
class Resource < ActiveRecord::Base
belongs_to :task
belongs_to :user
end
class User < ActiveRecord::Base
has_many :resources
has_many :tasks, :through=>:recources
end
class Task < ActiveRecord::Base
has_many :resources, :dependent => :destroy
has_many :comments, :dependent => :destroy
has_many :users, :through=>:resources
accepts_nested_attributes_for :resources,:comments
end
everything is ok - listing,creating etc. But i wanna make a view which user upload a text file that contains tasks (it is not important how i can read text file) so i read the file and fetch the tasks. I created a controller which name is upload :
class UploadController < ApplicationController
def index
end
def upload
flash[:notice]="Upload completed"
end
end
and index view like this :
<% if flash[:notice] %>
<p><%= flash[:notice] %></p>
<% end %>
<div class="upload">
<p>Select a project file</p>
<%= form_tag :controller=>:upload,:action => :upload,:method => :put do %>
<%= file_field 'Project File',:file %>
<%= submit_tag "Upload" %>
<% end %>
</div>
when i press upload button it gives me "Missing template upload/uploa...."
How can i accomplish this action, give me advice plz.
Thanks
Missing template upload/uploa...."
Rails is looking for a view: app/views/upload/upload.html.erb
PS. You'll need to add in :multipart => true in your form_for to upload a file ;)
Every action tries to render a template with the same name as itself if you don't specifically tell it what to render or redirect_to. So what you can do is this:
render :nothing => true
That should do what you want.
Also, the documentation is decent with regard to what you can do with render

Resources