How to bring the belongs_to table id to the form? - ruby-on-rails

In the index page i just filter the results by the projects_lkp_id.
def index
#filter = params[:projects_lkps_id] || ProjectsLkp.premitted_homes(current_user).first.id
#stock = Stock.where("projects_lkp_id = ?", #filter)
end
where projects_lkps_id has_many stocks
now my doubt is, when i create new stock how to bring this id to form? .
now my create method in controller is
def create
#stock = Stock.new(stock_params)
respond_to do |format|
if #stock.save
format.html{ redirect_to stocks_path(id: #stock.id), notice: "Item added to gallery" }
else
#stock = Stock.where(item: #stock.item).all
format.html { render 'index' }
end
end
end
stock_params is
params.require(:stocks).permit(:item,:unit,:projects_lkp_id)

If you have nested routes, like
resources :projects do
resources :stocks
end
Generated routes will be like -
project_stocks GET /projects/:project_id/stocks(.:format) stocks#index
POST /projects/:project_id/stocks(.:format) stocks#create
new_project_stock GET /projects/:project_id/stocks/new(.:format) stocks#new
edit_project_stock GET /projects/:project_id/stocks/:id/edit(.:format) stocks#edit
project_stock GET /projects/:project_id/stocks/:id(.:format) stocks#show
PATCH /projects/:project_id/stocks/:id(.:format) stocks#update
PUT /projects/:project_id/stocks/:id(.:format) stocks#update
DELETE /projects/:project_id/stocks/:id(.:format) stocks#destroy
Then you will have to have project_id in routes and you will be able to have project_id in controller, without having in form. Controller code will be like below
def create
#project = Project.find(params[:projects_id])
#stock = #project.stocks.new(stock_params)
respond_to do |format|
if #stock.save
format.html{ redirect_to projects_stocks_path(#project), notice: "Item added to gallery" }
else
#stock = Stock.where(item: #stock.item).all
format.html { render 'index' }
end
end
end
and stock_params will be -
params.require(:stocks).permit(:item,:unit)

Related

User information isn't storing to proper user

In my Users controller, I have the following method
def show
#user = User.find(params[:id])
if current_user.id == params[:id] # im not sure if this is right
#answer = Answer.new
else
#answer = Answer.find(params[:id])
end
end
where
class User
has_many :answers
end
and
class Answer
belongs_to :user
end
When I open another user (A) by the signed in user (B), I want A's quiz questions (which also belongs_to User through a has_one association) to have the answers by B.
As is, if B answers A's questions, and then I log in with A, they will have the same answers of the original B to A.
If it helps, in my Answers controller I have the following methods.
def create
#answer = current_user.answers.build(answer_params)
if #answer.save
flash[:success] = "Updated"
redirect_to '/'
else
render 'new'
end
end
def update
respond_to do |format|
#answer = Answer.find(params[:id])
if #answer.update(answer_params)
format.html { redirect_to '/', notice: 'Answers were successfully updated.' }
format.json { render :show, status: :ok, location: #answer }
else
format.html { render :edit }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
def answer_params
params.require(:answer).permit(:r1, :r2, :r3, :r4, :r5)
end
and I also have the migration
class AddUserIdToAnswers < ActiveRecord::Migration
def change
add_column :answers, :user_id, :integer
end
end
EDIT:
Quizzes Controller (belongs_to User, User has_one :quiz)
class QuizzesController < ApplicationController
def edit
#quiz = Quiz.find(params:[id])
end
def create
#quiz = current_user.build_quiz(quiz_params)
if #quiz.save
flash[:success] = "Updated"
redirect_to '/'
else
render 'new'
end
end
def update
respond_to do |format|
#quiz = Quiz.find(params[:id])
if #quiz.update(quiz_params)
format.html { redirect_to '/', notice: 'Quiz was successfully updated.' }
format.json { render :show, status: :ok, location: #quiz }
else
format.html { render :edit }
format.json { render json: #quiz.errors, status: :unprocessable_entity }
end
end
end
def quiz_params
params.require(:quiz).permit(:q1, :q2, :q3, :q4, :q5)
end
def show
#quizzes = Quiz.all
end
end
and my Routes.rb
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users
root to: 'welcome#landing'
resources :users, :quizzes, :answers
end
I am not gone through every aspect. But one issue in your show action.
if current_user.id == params[:id] # im not sure if this is right
With this you will not get new form. Because params[:id] type is string and current_user.id type is integer. So it will always return false.
Try change like :
if current_user.id == params[:id].to_i
Or compare user object directly
if current_user == #user
Try my suggestion helpisgood
def show
#user = User.find(params[:id])
if current_user == #user
#answer = Answer.new
else
#answer = Answer.find_by(user_id: #user.id)
end
end

Rails polymorphic commenting with permalink/token urls

In my app I have a commenting system that's largely based off of this railscast. Now in my models I'm changing the to_param to a random string so the id isn't in the url. But then that breaks commenting.
status.rb
class Status < ActiveRecord::Base
attr_accessible :content, :member_id, :document_attributes, :permalink
belongs_to :member
belongs_to :document
has_many :comments, as: :commentable, dependent: :destroy
before_create :make_it_permalink
accepts_nested_attributes_for :document
def to_param
permalink
end
private
def make_it_permalink
# this can create permalink with random 12 digit alphanumeric
self.permalink = SecureRandom.hex(12)
end
end
statuses_controller.rb
class StatusesController < ApplicationController
before_filter :authenticate_member!, only: [:index, :new, :create, :destroy]
before_filter :find_member
rescue_from ActiveRecord::RecordNotFound do
render file: 'public/404', status: 404, formats: [:html]
end
def index
#statuses = Status.order('created_at desc').page(params[:page]).per_page(21)
respond_to do |format|
format.html # index.html.erb
format.js
end
end
def show
#status = Status.find_by_permalink(params[:id])
#commentable = #status
#comments = #commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
#comment = #commentable.comments.new
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
end
end
def new
#status = Status.new
#status.build_document
respond_to do |format|
format.html # new.html.erb
format.json { render json: #status }
format.js
end
end
def create
#status = current_member.statuses.new(params[:status])
respond_to do |format|
if #status.save
#activity = current_member.create_activity(#status, 'created')
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to profile_path(current_member), alert: 'Post wasn\'t created. Please try again and ensure image attchments are under 10Mbs.' }
format.json { render json: #status.errors, status: :unprocessable_entity }
format.js
end
end
end
def destroy
#status = current_member.statuses.find(params[:id])
#activity = Activity.find_by_targetable_id(params[:id])
#commentable = #status
#comments = #commentable.comments
if #activity
#activity.destroy
end
if #comments
#comments.destroy
end
#status.destroy
respond_to do |format|
format.html { redirect_to profile_path(current_member) }
format.json { head :no_content }
end
end
private
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
def find_status
#status = current_member.statuses.find_by_permalink(params[:id])
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_filter :authenticate_member!
before_filter :load_commentable
before_filter :find_member
def index
redirect_to root_path
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
#comments = #commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
#comment.member = current_member
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back }
format.json
format.js
end
end
end
def destroy
#comment = Comment.find(params[:id])
respond_to do |format|
if #comment.member == current_member || #commentable.member == current_member
#comment.destroy
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
format.json
format.js
end
end
end
private
# def load_commentable
# resource, id = request.path.split('/')[1,2] # photos/1/
# #commentable = resource.singularize.classify.constantize.find(id) # Photo.find(1)
# end
# alternative option:
def load_commentable
klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
#def load_commentable
# #commentable = params[:commentable_type].camelize.constantize.find(params[:commentable_id])
#end
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
end
The problem lies in the load_commentable method in the comments_controller. I've tried a couple different variations of the method but the second one works best for my app and it was working when the url's had their id's in them. But since I overwrote the to_param to use my random permalink commenting stopped working because it's trying to find theid where it equals the permalink. Since it seems to try to find the id through the url, how do I pass the the actual id and not the permalink or how do I find commentable by it's permalink instead of id?
It's hard to tell if your param will always be the value of id or always be the permalink, or will sometimes be an id and sometimes a permalink.
If it will always be a permalink, then do:
#commentable = klass.find_by_permalink(params["#{klass.name.underscore}_id"])
instead of
#commentable = klass.find(params["#{klass.name.underscore}_id"])
If it is sometimes id and sometimes other, then you will need make logic to determine which is needed based on the class.

simple query on scaffolding rails

So my simple question is, i want to call a mailer if particular column is updated in database with the form based on below controller. But i dont know how to take the column name ... I am doing like if #style.category after if #style.save but not working.
Controller
def new
#style = Style.new
#users = User.where('username <> ?', current_user.username)
respond_to do |format|
format.html # new.html.erb
format.json { render json: #style }
end
end
def create
#style = Style.new(params[:style])
#style.sender = current_user
respond_to do |format|
if #style.save,
### want to call mailer here , based on if column "category" is updated or not
if #style.receiver
format.html { redirect_to user_path(#style.receiver.username), notice: "successs!"}
else
format.html { redirect_to root_path, notice: 'Success!' }
end
add a after_save callback inside the model can help
class Style < ActiveRecord::Base
after_save :send_email
def send_email
if changed_attributes.has_key?('category')
call the mailer here
end
end
end

Rails app Active Record Reputation System Error Caller Id

I have just finished implementing ARRS, following R. Bates Railscasts #364.
I changed it to fit my app, so
a user votes on a movie in show view
Which is quite different to r. bates' one where
a user votes on a haiku in index view
And upon launching, the buttons look fine and they appear on the show view.
yet when i click on one this error appears
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
Any ideas anyone?
Movies_controller.rb
class MoviesController < ApplicationController
# GET /movies
# GET /movies.json
def index
#search = Movie.search(params[:q])
#movies = Movie.all
end
# GET /movies/1
# GET /movies/1.json
def show
#movies = Movie.find_with_reputation(:votes, :all, order: 'votes desc')
#search = Movie.search(params[:q])
#movie = Movie.find(params[:id])
end
def search
#search = Movie.search(params[:q])
#movies = #search.result
respond_to do |format|
format.html # index.html.erb
format.json { render json: #movies }
end
end
# GET /movies/new
# GET /movies/new.json
def new
#search = Movie.search(params[:q])
#movie = Movie.new
end
# GET /movies/1/edit
def edit
#search = Movie.search(params[:q])
#movie = Movie.find(params[:id])
end
# POST /movies
# POST /movies.json
def create
#search = Movie.search(params[:q])
#movie = Movie.new(params[:movie])
respond_to do |format|
if #movie.save
format.html { redirect_to #movie, notice: 'Movie was successfully created.' }
format.json { render json: #movie, status: :created, location: #movie }
else
format.html { render action: "new" }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
# PUT /movies/1
# PUT /movies/1.json
def update
#search = Movie.search(params[:q])
#movie = Movie.find(params[:id])
respond_to do |format|
if #movie.update_attributes(params[:movie])
format.html { redirect_to #movie, notice: 'Movie was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
# DELETE /movies/1
# DELETE /movies/1.json
def destroy
#movie = Movie.find(params[:id])
#movie.destroy
end
def vote
value = params[:type] == "up" ? 1 : -1
#movie = Movie.find(params[:id])
#movie.add_evaluation(:votes, value, current_user)
redirect_to :back, notice: "Thank you for voting!"
end
end
Movie.rb
has_reputation :votes, source: :user, aggregated_by: :sum
User.rb
has_reputation :votes, source: {reputation: :votes, of: :movies}, aggregated_by: :sum
show.html.erb //movies
<div class="ratings">
<em>
<%= pluralize #movie.reputation_for(:votes).to_i, "vote" %>
| <%= link_to "up", vote_movie_path(#movie, type: "up"), method: "post" %>
| <%= link_to "down", vote_movie_path(#movie, type: "down"), method: "post" %>
</em>
</div>
routes.rb
resources :movies do
member { post :vote }
end
def vote
value = params[:type] == "up" ? 1 : -1
#movie = Movie.find(params[:id])
#movie.add_evaluation(:votes, value, current_user)
redirect_to :back, notice: "Thank you for voting!"
end
the problem might be here:
add_evaluation(:votes, value, current_user)
requires current_userthat you don't have. Devise documentations says you need to include
before_filter :authenticate_user! in the conotroller to use the current_user helper.
Pay more attention to documentations when using a gem.
EIDT after chatting to solve this issue the acts_as_votable gem was used
https://github.com/ryanto/acts_as_votable instead of Active Record Reputation System
here the problem is in your add_evaluation line
change it to
'add_or_update_evaluation(:votes, value, current_user)'
this will add and also update the evaluation part.

How do I access an associated model of an associated model?

I have a Topic which has_many Posts. Each Post belongs to a User, and each User has_one Profile.
In my "show" page for a specific Topic, I try to display profile information of the user who created the post:
<% #topic.posts.each do |post| %>
<%= post.user.profile.first_name %>
<% end %>
I get the following error:
undefined method `profile' for nil:NilClass
Any idea why it does not allow me to access the profile? Please advise.
My Topic controller is as follows:
class TopicsController < ApplicationController
# GET /topics
# GET /topics.json
add_breadcrumb :index, :topics_path
def index
if params[:tag]
#topics = Topic.tagged_with(params[:tag])
else
#topics = Topic.all
end
#newtopic = Topic.new
respond_to do |format|
format.html # index.html.erb
format.json { render json: #topics }
end
end
# GET /topics/1
# GET /topics/1.json
def show
#topic = Topic.find(params[:id])
#posts = #topic.posts
#newpost = #topic.posts.build
add_breadcrumb #topic.name
respond_to do |format|
format.html # show.html.erb
format.json { render json: #topic }
end
end
# GET /topics/new
# GET /topics/new.json
def new
add_breadcrumb :new, :topics_path
#topic = Topic.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #topic }
end
end
# GET /topics/1/edit
def edit
#topic = Topic.find(params[:id])
end
# POST /topics
# POST /topics.json
def create
#topic = Topic.new(params[:topic])
#topic.user_id = current_user.id
#topic.last_poster_id = current_user.id
#topic.last_post_at = Time.now
respond_to do |format|
if #topic.save
format.html { redirect_to #topic, notice: 'Topic was successfully created.' }
format.json { render json: #topic, status: :created, location: #topic }
else
format.html { render action: "new" }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# PUT /topics/1
# PUT /topics/1.json
def update
#topic = Topic.find(params[:id])
respond_to do |format|
if #topic.update_attributes(params[:topic])
format.html { redirect_to #topic, notice: 'Topic was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /topics/1
# DELETE /topics/1.json
def destroy
#topic = Topic.find(params[:id])
#topic.destroy
respond_to do |format|
format.html { redirect_to topics_url }
format.json { head :no_content }
end
end
end
Your error is caused by this line in the show action #topic.posts.build and this line in the view #topic.posts.each. Since you are building a new post in the controller, #topic.posts includes that new record which most probably have the user as nil. So the solution to your problem is to use #posts instead of #topic.posts in your view.
Check your database. Its very likely that in your database there is a post which corresponds to no user. Since the user for that post is none, the profile becomes undefined for nil:NilClass which is user(null).
This happens mostly when you creates the post that belongs to user but then you deletes the user that belongs to that post from database.
The correct way is to impose a constraint in your user model that should be-
class Post
belongs_to :user, :dependent => :destroy
end
So if the user gets deleted, the corresponding posts of that user also get deleted.
Please note that it is not a good practice to directly delete records from database after imposing the relationship between them using tables.

Resources