NoMethodError when I try to access localhost:3000/home - ruby-on-rails

I'm trying to access the 'home' page of my Rails app by going to localhost:3000/home
When I try the link above, however, I get the below error message --- however this doesn't make sense to me because 'category' is just a parameter for an order. Order has a category, store, items and other parameters.
My code is below. What am I doing wrong here?
Showing /Users/fk/tenence_ai/app/views/tenence/home.html.erb where line #49 raised:
undefined method `category' for #<Order:0x007f8ed99c8500>
Extracted source (around line #49):
47 <div>
48 <%= form_for :order, url: orders_path do |f| %>
49 <%= f.text_field :category,:id=> 'category',:style=>'display:none' %>
ORDERS CONTROLLER
class OrdersController < ApplicationController
respond_to :html, :json
def show
#order = Order.find(params[:id])
#idx = Order.last.id
render json: #order
end
def create
#order = Order.new(order_params)
#order.save
end
def edit
#order = Order.find(params[:id])
end
def update
#order = Order.find(params[:id])
#order.update(order_params)
end
respond_to :html, :json
private
def order_params
params.require(:order).permit(:address,:store,:name,:items,:category,:status,:total,{:item => []},{:price => []})
end
end
ORDER MODEL
class Order < ApplicationRecord
end
RELEVANT MIGRATION
class CreateOrders < ActiveRecord::Migration[5.0]
def change
create_table :orders do |t|
t.string :name
t.text :address
t.string :store
t.text :items
t.timestamps
end
end
end

It seems that you want to add category field:
Adding in params.require is good but you also need to add attr_accessor :category in your model.
class Order < ApplicationRecord
attr_accessor :category
end
attr_accessor can be used for values you don't want to store in the database directly and that will only exist for the life of the object.

Related

Sort a list of Items in Rails based on Likes done by Users

I'm new to ruby on rails so please forgive the question. I tried following this example Rails sort tags by most used (tag.posts.count) but kept getting an error "undefined method `order' for Items:Module". I am trying to sort a list of items based on an item's likes. So an item with 5 likes should be placed above an item with only 3 likes. I have listed below all my relevant code down below. Thank you so much guys!!
Like.rb
class Like < ApplicationRecord
belongs_to :item, :counter_cache => true
belongs_to :user
end
Likes_controller.rb
class Items::LikesController < ApplicationController
before_action :authenticate_user!
before_action :set_book
def create
#item.likes.where(user_id: current_user.id).first_or_create
respond_to do |format|
format.html {redirect_to #item}
format.js
end
end
def destroy
#item.likes.where(user_id: current_user.id).destroy_all
respond_to do |format|
format.html {redirect_to #item}
format.js
end
end
private
def set_book
#item = Item.find(params[:item_id])
end
end
Item.rb
class Item < ApplicationRecord
has_many :likes, :counter_cache => true
users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user!
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
#items = Item.all
Items.order('likes_count')
end
def show
#items = Item.find(params[:id])
end
private
def set_user
#item = Item.find(params[:id])
end
end
index.html.erb
<% #items.each do |item| %>
<%= item.product %>
<div><%= image_tag(item.avatar.url(:thumb)) %></div>
<% end %>
Migrations Relevant
class AddLikecountsToItem < ActiveRecord::Migration[5.0]
def change
add_column :items, :likes_count, :integer, :null => false, :default => 0
end
end
class CreateLikes < ActiveRecord::Migration[5.0]
def change
create_table :likes do |t|
t.integer :user_id
t.integer :item_id
t.timestamps
end
end
end
in users_controller.rb
def index
#items = Item.order('likes_count')
end

rake aborted! TypeError: Parts is not a class

Well I got another error now with my database this time saying one of the classes I made "Parts" is not a class. I can't seem to know where this is tracing from
and here is my Parts database values (the file name is parts.rb)
class Parts < ActiveRecord::Migration
def change
create_table :parts do |t|
t.string :name
t.text :description
t.integer :category_id
end
end
end
my parts controller:
class PartsController < ApplicationController
before_filter :authorize, :except => :index
def index
#parts = Part.all
end
def new
#part = Part.new
end
def show
#part = Part.find(params[:id])
end
def create
#part = Part.new(part_params)
if #part.save
redirect_to part_path(#part)
end
end
def edit
#part = Part.find(params[:id])
end
def update
#part = Part.find(params[:id])
if #part.update_attributes(part_params)
redirect_to #part
end
end
def destroy
#part = Part.find(params[:id])
#part.destroy
redirect_to parts_path
end
private
def part_params
params.require(:part).permit(:description, :name)
end
end
my parts model is just
class Part < ActiveRecord::Base
end
Thanks for any help
It may just not like 'Parts' as a class name conflicting with something in the model or controller. or you have a Parts module defined somewhere?
I suggest changing the migration class name to, say, CreateParts, ie.
def CreateParts < ActiveRecord::Migration
def change
…
end
end
And I'd change the filename too just in case (2016…09_create_parts.rb)
Hope you generate the migration file with model by command like
bundle exec rails g model Part name:string description:text category_id:integer
it will create the migration file 2016...09_create_parts.rb
and it will be look like
def CreateParts < ActiveRecord::Migration
def change
create_table :parts do |t|
t.string :name
t.text :description
t.integer :category_id
end
end
end

Rails upload csv or text file with associations

I am building a rails application that associates serial #'s with software titles. For instance, I have a software title, and need to be able to upload batches of serial #'s(codes) and associate it with that specific software title. It needs to be simple enough for a user(authenticated) to click an upload link, select a software title from a dropdown and hit import. Here is what I have so far... It does not necessarily have to be a csv it could be a text file too. I just need help figuring out the best way to accomplish this.
Code Upload UI
Code Schema
create_table "codes", force: :cascade do |t|
t.integer "software_id"
t.integer "user_id"
t.string "label"
t.string "code"
t.string "in_use"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "codes", ["software_id"], name: "index_codes_on_software_id"
add_index "codes", ["user_id"], name: "index_codes_on_user_id"
Code 'form' for UI
<%= simple_form_for(#code) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.association :software %>
<%= f.input :label %>
<%= f.input :code %>
</div>
<div class="form-actions">
<%= f.file_field :code %>
<br>
<%= f.button :submit, "Upload Codes", class: 'btn btn-warning' %>
</div>
<br>
<% end %>
Code.rb Model
class Code < ActiveRecord::Base
belongs_to :software
belongs_to :user
accepts_nested_attributes_for :software
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
Code.create! row.to_hash
end
end
end
Software.rb Model
class Software < ActiveRecord::Base
has_many :software_assigns
has_many :products, through: :software_assigns
has_many :software_downloads
has_many :codes
end
Codes Controller
class CodesController < ApplicationController
before_action :authenticate_user!
before_action :verify_admin
before_action :set_code, only: [:show, :edit, :update, :destroy]
# GET /codes
# GET /codes.json
def index
#codes = Code.all
end
# GET /codes/1
# GET /codes/1.json
def show
end
# GET /codes/new
def new
#code = Code.new
end
# GET /codes/1/edit
def edit
end
# POST /codes
# POST /codes.json
def create
#code = Code.new(code_params)
respond_to do |format|
if #code.save
format.html { redirect_to #code, notice: 'Codes were successfully created.' }
else
format.html { render :new }
end
end
end
# PATCH/PUT /codes/1
# PATCH/PUT /codes/1.json
def update
respond_to do |format|
if #code.update(code_params)
format.html { redirect_to #code, notice: 'Codes were successfully updated.' }
else
format.html { render :edit }
end
end
end
# DELETE /codes/1
# DELETE /codes/1.json
def destroy
#code.destroy
respond_to do |format|
format.html { redirect_to codes_url, notice: 'Codes were successfully destroyed.' }
end
end
def import
Code.import(params[:file])
redirect_to codes_path, notice: 'Codes were successfully uploaded!'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_code
#code = Code.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def code_params
params.require(:code).permit(:software_id, :label, :code)
end
end
Ok - doing a lot of communication in the comments and I think I can put together an answer now.
So, as per my edit to pitabas prathal's answer, you need to look for by the :code key in the code_params hash, but since the Code class has no idea that you've got a code_params[:software_id] to refer to, you'll need to pass that along. So your import method becomes:
code.rb
def self.import(file, software_id)
CSV.foreach(file.path, headers: true) do |row|
code = Code.new row.to_hash
code.software_id = software_id
code.save!
end
end
Then, your call to this method with the new argument, from the create action (or your import method on the controller):
Code.import(code_params[:code], code_params[:software_id])
Now, you are giving your Code class all the information it needs to associate the new Code objects with the appropriate Software object.
Edit
In your GoRails post, Chris Oliver's answer would also work, with one edit:
#software = Software.find(params[:software_id])
will not work - params[:software_id] is nil. You can access software_id from the code_params hash:
#software = Software.find(code_params[:software_id])
or by adding the [:code] key in to the params reference like so:
#software = Software.find(params[:code][:software_id])
since [:software_id] is inside the [:code] array in the params hash.

How to access current_user variable in controller or model?

I have 1:N relationship between user and post model. I want to access user_id in post model. I tried it by accessing current_user but it's throwing cannot find current_user variable.
My userModel class:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :validatable
has_many :post
validates_format_of :email, with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
end
MyPostModel class:
class Post < ActiveRecord::Base
belongs_to :user
before_create :fill_data
validates_presence_of :name, :message => 'Name field cannot be empty..'
def fill_data
self.is_delete = false
self.user_id = current_user # here I am getting the error
end
end
MyPostController class
class PostController < ApplicationController
before_action :authenticate_user!
def index
#post = Post.all
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to action: 'index'
else
render 'new'
end
end
.....
private
def post_params
params.require(:post).permit(:name,:user_id,:is_delete)
end
end
I can access the before_action :authenticate_user! in Post controller but not current_user in post model or controller. What I am doing wrong here in Post.fill_data. self.user_id?
Rest of the code is working fine and I can see the new entry of :name and :is_delete in sqlite3 database (when I am commenting self.user_id line in Post class).
Edit-1
I already have migration class for post
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :name
t.boolean :is_delete
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
In Rails your models should not be aware of the apps current user or any other state. They only need to know about themselves and the objects they are directly related to.
The controller on the other hand is aware of the current user.
So the proper way to do this would be to remove the fill_data callback from Post. And do it in the controller:
class PostController < ApplicationController
before_action :authenticate_user!
def index
#post = Post.all
end
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to action: 'index'
else
render 'new'
end
end
private
def post_params
params.require(:post).permit(:name,:user_id,:is_delete)
end
end
You should also set the default for your is_delete column in the database instead, but if you want to rock it like a pro use an enum instead.
Create a migration rails g migration AddStateToUsers and fill it with:
class AddStateToUsers < ActiveRecord::Migration
def change
add_column :users, :state, :integer, default: 0
remove_column :users, :is_delete
add_index :users, :state
end
end
We then use the rails enum macro to map state to a list of symbols:
class Post
enum state: [:draft, :published, :trashed]
# ...
end
That lets you do Post.trashed to get all posts in the trash or post.trashed? to check if a specific post is trashed.
notice that I use trashed instead of deleted because ActiveRecord has build in deleted? methods that we don't want to mess with.
You are trying to add current_user.id in post model using before_create call back. but better to do is use this
In posts_controller.rb
def new
#post = current_user.posts.new
end
def create
#post = current_user.posts.create(posts_params)
end
This will create a post for the current user.
Your fill_data method would be
def fill_data
self.is_delete = false
end

Unable to update attribute - undefined method

Missing something fundamental here. Unable to update items_loaded once REST Client is done fetching some items from this API.
Live app which you can run on the fly: http://runnable.com/VW9rQx-KiIFfmpII/ajax-affiliates
undefined method `items_loaded=' for #<Class:0x000000037cce20>
app/models/affiliate.rb:17:in `set_items_loaded'
app/controllers/main_controller.rb:8:in `index'
main_controller.rb
class MainController < ApplicationController
def index
# Delay fetching
# #products = Affiliate.fetch
#products = Affiliate.delay.fetch
# Let us know when fetching is done
Affiliate.set_items_loaded
end
def check_items_loaded
#items_status = Affiliate.items_loaded
respond_to do |wants|
wants.js
end
end
end
affiliate.rb
require "rest_client"
class Affiliate < ActiveRecord::Base
def self.fetch
response = RestClient::Request.execute(
:method => :get,
:url => "http://api.shopstyle.com/api/v2/products?pid=uid7849-6112293-28&fts=women&offset=0&limit=10"
)
#products = JSON.parse(response)["products"].map do |product|
product = OpenStruct.new(product)
product
end
end
def self.set_items_loaded
self.items_loaded = true
end
end
20150604120114_add_items_loaded_to_affiliates.rb
class AddItemsLoadedToAffiliates < ActiveRecord::Migration
def self.up
change_table :affiliates do |t|
t.column :items_loaded, :boolean, default: false
end
end
def self.down
change_table :affiliates do |t|
t.remove :items_loaded
end
end
end
Actually, in your class Affiliate, you defined the method self.set_items_loaded which get all Affiliate object and set attribute items_loaded to true on each object of this class.
If you really want to do that, you should write that
affiliate.rb
def self.set_items_loaded
self.update_all(items_loaded: true)
end
main_controller.rb
Affiliate.set_items_loaded
If you just want to update one object of Affiliate to set item_loaded to true, you should define your method that way and use it on one object
affiliate.rb
def set_items_loaded
self.items_loaded = true
end
main_controller.rb
Affiliate.first.set_items_loaded # to get the first object of Affiliate updated

Resources