I am trying to use Rails' active record to generate something before_save and save it to a field. It's using two tables (Message and Spec)
My models/message.rb file looks like this:
class Message < ApplicationRecord
has_many :specs
accepts_nested_attributes_for :specs
before_save :generate_output
def generate_output
self.output = "hola"
specs_array = Spec.where(message_id: self.id).order('id asc')
specs_array.each do |spec|
self.output = "hello"
if spec.call
self.output += Message.find(name: spec).output
else
self.output += spec.specification
end
end
self.output
end
end
and my models/spec.rb file:
class Spec < ApplicationRecord
belongs_to :message
end
And here is my schema:
ActiveRecord::Schema.define(version: 20171121153642) do
enable_extension "plpgsql"
create_table "messages", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "output"
end
create_table "specs", force: :cascade do |t|
t.string "specification"
t.boolean "call"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "message_id"
t.index ["message_id"], name: "index_specs_on_message_id"
end
add_foreign_key "specs", "messages"
end
I have a message form, that upon submission, saves a 'name' to Message table and 3 Specifications (and their message_id) to Spec table. It should also generate and save an output (as you can see in the message model) based on the specs in the Message table.
but these two lines of code in the model do not work:
specs_array = Spec.where(message_id: self.id).order('id asc')
specs_array.each do |spec|
I know the ones before them are working, because when I create a new message, its output is saved as 'hola' and if these two lines work, it should be saved as 'hello'+ whatever the message is.
I have tried the query in rails console, and it totally works fine, any idea why it's not working in the app?
thanks!
edit:
My controller method that calls for save (it's Rails generic method):
def create
#message = Message.new(message_params)
respond_to do |format|
if #message.save
format.html { redirect_to #message, notice: 'Message was successfully created.' }
format.json { render :show, status: :created, location: #message }
else
format.html { render :new }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
and the private method for messasge_params:
def message_params
params.require(:message).permit(:name, specs_attributes: [:id, :call, :specification])
end
Try to rewrite your like:
specs_array = Spec.where(message_id: self.id).order('id asc')
To:
specs_array = specs.order(:id)
Write a comment whether that helped?
Related
I have an app where I post school classes and users can book classes. Now I have added stripe payments, with a monthly subscription. I would like to know how to show users how many classes they have booked since their monthly payment started.
I have tried this:
<%= #mylessons_lessons.count %>
But this only gives me the total lessons (classes) someone has booked since the beginning of time.
How could I find the booked lessons from each user depending on the date their subscription started and that only takes into account those of the last monthly subscription.
This is my lessons controller:
class LessonsController < ApplicationController
before_action :set_lesson, only: [:show, :edit, :update, :destroy, :mylessons]
before_action :authenticate_user!
# GET /lessons
# GET /lessons.json
def index
#lessons = Lesson.order(created_at: :asc)
end
# GET /lessons/1
# GET /lessons/1.json
def show
end
# GET /lessons/new
def new
#lesson = current_user.lessons.build
redirect_to root_path, warning: "You are not authorized" unless #current_user.admin?
end
# GET /lessons/1/edit
def edit
redirect_to root_path, warning: "You are not authorized" unless #current_user.admin?
end
# POST /lessons
# POST /lessons.json
def create
#lesson = current_user.lessons.build(lesson_params)
respond_to do |format|
if #lesson.save
format.html { redirect_to #lesson, notice: 'lesson was successfully created.' }
format.json { render :show, status: :created, location: #lesson }
else
format.html { render :new }
format.json { render json: #lesson.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /lessons/1
# PATCH/PUT /lessons/1.json
def update
redirect_to root_path, warning: "You are not authorized" unless #current_user.admin?
respond_to do |format|
if #lesson.update(lesson_params)
format.html { redirect_to #lesson, notice: 'lesson was successfully updated.' }
format.json { render :show, status: :ok, location: #lesson }
else
format.html { render :edit }
format.json { render json: #lesson.errors, status: :unprocessable_entity }
end
end
end
# DELETE /lessons/1
# DELETE /lessons/1.json
def destroy
redirect_to root_path, warning: "You are not authorized" unless #current_user.admin?
#lesson.destroy
respond_to do |format|
format.html { redirect_to lessons_url, notice: 'lesson was successfully destroyed.' }
format.json { head :no_content }
end
end
# Add and remove lessons to mylessons
# for current_user
def mylessons
type = params[:type]
if type == "add"
current_user.mylessons_additions << #lesson
redirect_to root_path, notice: "#{#lesson.title} ha sido aƱadida a tus clases"
elsif type == "remove"
current_user.mylessons_additions.delete(#lesson)
redirect_to root_path, notice: "#{#lesson.title} ha sido eliminada de tus clases"
else
# Type missing, nothing happens
redirect_to lesson_path(#lesson), notice: "Parece que no ha sucedido nada, prueba otra vez!"
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_lesson
#lesson = Lesson.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def lesson_params
params.require(:lesson).permit(:title, :description, :teacher, :thumbnail, :user_id, :date, :datetime, :lessonlink, :giphyimage, :game, :externalmaterial, :lessonage )
end
end
and my mylessons controller:
class MylessonsController < ApplicationController
before_action :set_lesson, only: [:show, :edit, :update, :destroy, :mylessons, :lessons]
before_action :authenticate_user!
def index
#mylessons_lessons = current_user.mylessons_additions
#lessons = Lesson.order(created_at: :asc)
end
end
and the schema from my db payments:
create_table "pay_charges", force: :cascade do |t|
t.bigint "owner_id"
t.string "processor", null: false
t.string "processor_id", null: false
t.integer "amount", null: false
t.integer "amount_refunded"
t.string "card_type"
t.string "card_last4"
t.string "card_exp_month"
t.string "card_exp_year"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "owner_type"
t.index ["owner_id"], name: "index_pay_charges_on_owner_id"
end
create_table "pay_subscriptions", id: :serial, force: :cascade do |t|
t.integer "owner_id"
t.string "name", null: false
t.string "processor", null: false
t.string "processor_id", null: false
t.string "processor_plan", null: false
t.integer "quantity", default: 1, null: false
t.datetime "trial_ends_at"
t.datetime "ends_at"
t.datetime "created_at"
t.datetime "updated_at"
t.string "status"
t.string "owner_type"
end
create_table "plans", force: :cascade do |t|
t.string "name"
t.integer "amount", default: 0, null: false
t.string "interval"
t.jsonb "details", default: {}, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "trial_period_days", default: 0
end
Conceptually the steps are:
check when user (paied) subscribed
get all classes from the date of subscription
show classes or number of classes in your view
You could use a scope in the model you want to check for start date of subscription, something like
scope :classes_after_subscription, ->(date) { where("created_at >= ?", date) }
and call it in your controller or in a decorator to use it in a view
classes_after_subscription("pass_user_sub_date_HERE").size
I am stock trying to write the code that make possible for users to update a balance every time they make a transaction.
This is a simple bartering application:
The user can either offer products for sale or buy products from other users.
The user pays with a kind of virtual money (units).
When a user clicks in Order a transaction is executed.
The Models are: User, Product and Order.
If the user orders a product ( here order=transaction) I expect that the orders price (here price=amount) will be added to the users balance:
My expectation is that this code in orders_controller could make that the amount of #price pass and adds to #balance and makes possible the update:
#user.balance = balance: (#user.balance += #order.price)
But this is not working
I have tried as well in orders_controller with this:
def balance
if #order.save
#user.balance_update!(balance: #user.balance + #order.price)
end
end
But doesnt work.
What could be wrong with this code?
Please help!
These are the relevant files:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :fullname,presence: true
validates :description, presence: false
validates :balance, presence: true, numericality:true
before_validation :load_defaults
def load_defaults
if self.new_record?
self.balance = 100
end
end
has_many :products
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :product
validates :price, presence: true
validates :product_id, presence: true
validates :user, presence: true
end
class Product < ActiveRecord::Base
belongs_to :user
has_many :orders
end
class OrdersController < ApplicationController
before_action :authenticate_user!
def create
#order = current_user.orders.create(order_params)
#user.balance = balance: (#user.balance += #order.price)
redirect_to user_orders_path
end
end
def user_orders
#orders = current_user.orders
end
private
def order_params
params.require(:order).permit(:price, :user_id)
end
end
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#products = #user.products
end
end
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:show]
def index
#products = current_user.products
end
def show
end
def new
#product = current_user.products.build
end
def edit
end
def create
#product = current_user.products.build(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_product
#product = Product.find(params[:id])
end
def product_params
params.require(:product).permit(:name, :description, :price)
end
end
<p>
User name: <%= #user.fullname %>
</p>
<p>
Balance: <%= #user.balance %>
</p>
ActiveRecord::Schema.define(version: 20171031150052) do
create_table "orders", force: :cascade do |t|
t.integer "user_id"
t.integer "product_id"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "transactiontype"
t.integer "buyer_id"
t.integer "seller_id"
end
add_index "orders", ["product_id"], name: "index_orders_on_product_id"
add_index "orders", ["user_id"], name: "index_orders_on_user_id"
create_table "products", force: :cascade do |t|
t.string "name"
t.text "description"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
add_index "products", ["user_id"], name: "index_products_on_user_id"
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "fullname"
t.string "description"
t.integer "balance"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Rails.application.routes.draw do
devise_for :users
get 'pages/index'
resources :products
resources :users
resources :products do
resources :orders, only: [:create]
end
resources :orders, only: [:show]
get '/user_orders' => 'orders#user_orders'
end
If you assign an attribute directly you just assign a value and need call save yourself:
#user.balance = #order.price
#user.save!
Or you can use update (there is no balance_update), then you call it with a hash:
#user.update!(balance: #user.balance + #order.price)
Try
#user.update(balance: #user.balance + #order.price)
I added a new column named "version" to a table in Rails using a migration and manually added the corresponding parameter to the strong parameters permitted in the corresponding controller:
def endpoint_params
params.require(:endpoint).permit(:hostname, :username, :password, :connection_string, :entity_id, :created_at,
:updated_at, :endpoint_type_id, :endpoint_app_id, :environment_id, :created_by,
:updated_by, :version)
end
However, when I try to set that new parameter in the update action and save it to the database, it doesn't get saved at all. The code that I'm using is:
def update
begin
#environment = Environment.find(params[:env])
version_no = (EndpointsFile.where("environment_id = ?", #environment.id).maximum('version') || 0) + 1
#endpoint.updated_by = current_user.id
#endpoint.version = version_no
respond_to do |format|
if #endpoint.update(endpoint_params)
#endpoints = Endpoint.where("environment_id = ? and id <> ?", #environment.id, #endpoint.id)
EndpointsFile.create!(version: version_no, date: Time.now, environment_id: #environment.id)
#endpoints.each do |e|
e.version = version_no
e.save
puts "e.version: #{e.version}" **=> HERE IT PRINTS e.version: and the field is null in the database**
end
format.html { redirect_to env_endpoints_path(env: #environment.id), notice: t('.notice') }
format.json { render :show, status: :ok, location: #endpoint }
else
format.html { render :edit }
format.json { render json: #endpoint.errors, status: :unprocessable_entity }
end
end
rescue => exception
logger.error { "endpoints_controller.update -> Ocorreu um erro ao atualizar o endpoint: #{exception.message}" }
respond_to do |format|
format.html { redirect_to env_endpoints_path(env: #environment.id), alert: "Ocorreu um erro ao atualizar o endpoint: #{exception.message}" and return }
format.json { render json: #endpoint.errors, status: :unprocessable_entity }
end
end
end
This is the Endpoint model:
class Endpoint < ApplicationRecord
belongs_to :entity
belongs_to :environment
belongs_to :endpoint_app
belongs_to :endpoint_type
has_many :configs_histories
has_paper_trail
end
The table in DB is:
create_table "endpoints", force: :cascade do |t|
t.string "hostname"
t.string "username"
t.string "password"
t.string "connection_string"
t.integer "entity_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "endpoint_type_id"
t.integer "endpoint_app_id"
t.integer "environment_id"
t.integer "created_by"
t.integer "updated_by"
t.integer "version"
t.index ["endpoint_app_id"], name: "index_endpoints_on_endpoint_app_id"
t.index ["endpoint_type_id"], name: "index_endpoints_on_endpoint_type_id"
t.index ["entity_id"], name: "index_endpoints_on_entity_id"
t.index ["environment_id"], name: "index_endpoints_on_environment_id"
end
What am I doing wrong? Why doesn't the command e.save work?
Finally found the solution.
version is a reserved keyword so it can't be used as a column name.
check link: http://reservedwords.herokuapp.com/words?page=9
Since you are calculating version_no inside update, you don't have to pass it in controller or permit in strong parameters, just do the following
#endpoint.update(endpoint_params.merge(version: version_no))
Generator has_many results
Result belongs_to generator
When i run rails console : Result.find(1) , the generator_id= nil. Why is this so ??? When i'm creating the data , the routes are like this :
localhost:3000/generator/1/results/new
It has got no error with the following code. BUt how come when i have this in my Generator/index.html
<% generator.results.each do |result| %>
<td><%= result.ncbi_ref_seq %></td>
<td><%= result.genome_sample %></td>
<td><%= result.binding_times %></td>
<%end%>
they're empty. Whereas the #generators.each do |generator| gives me the values of the generator. In other words, the result's value belonging to this generator is empty but the generator values are shown. What i want is to have all generators and their result value to be shown. Can some1 help me ?
Generator.model
class Generator < ActiveRecord::Base
has_many :results , :dependent => :destroy
attr_accessible :choice, :primer_length, :random_primer_generated, :genome_sample, :generator_id
GeneratorController.rb
def index
#generators = Generator.all
end
def create
#generator = Generator.new(generator_params)
#generator.choice = params[:choice]
if params[:choice] == 'Randomly'
#generator.random_generate(generator_params)
elsif params[:choice] == 'No_of_ATGC'
#generator.no_ATGC(params[:no_A],params[:no_T],params[:no_G],params[:no_C])
elsif params[:choice] == 'Seating'
#generator.seating(params[:user_seq])
end
#generator.result_choice=params[:result_choice]
respond_to do |format|
if #generator.save
if #generator.result_choice == 'Yes'
format.html { redirect_to(new_generator_result_path(#generator)) }
else
format.html { redirect_to #generator, notice: 'Result was successfully created.' }
format.json { render action: 'show', status: :created, location: #generator }
end
else
format.html { render action: 'new' }
format.json { render json: #generator.errors, status: :unprocessable_entity }
end
end
end
Result Model
class Result < ActiveRecord::Base
attr_accessible :ncbi_ref_seq,:genome_seq, :genome_sample
belongs_to :generator, foreign_key: "generator_id"
ResultController
def index
#results = Result.all
end
def create
#result = Result.new(result_params)
#result.generate_result(result_params)
respond_to do |format|
if #result.save
format.html { redirect_to #result, notice: 'Result was successfully created.' }
format.json { render action: 'show', status: :created, location: #result }
else
format.html { render action: 'new' }
format.json { render json: #result.errors, status: :unprocessable_entity }
end
end
end
schema.rb
create_table "generators", force: true do |t|
t.integer "primer_length"
t.integer "no_A"
t.integer "no_T"
t.integer "no_G"
t.integer "no_C"
t.string "choice"
t.string "random_primer_generated"
t.string "user_seq"
t.string "c_primer"
t.string "result_choice"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "results", force: true do |t|
t.integer "generator_id"
t.string "ncbi_ref_seq"
t.string "genome_seq"
t.string "genome_sample"
t.integer "binding_times"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "results", ["generator_id"], name: "index_results_on_generator_id"
create_table "results_{:column_options=>{:null=>true}}", id: false, force: true do |t|
t.integer "result_id", null: false
t.integer "{:column_options=>{:null=>true}}_id", null: false
t.integer "generator_id"
t.string "ncbi_ref_seq"
t.string "genome_seq"
t.string "genome_sample"
t.integer "binding_times"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "results_{:column_options=>{:null=>true}}", ["generator_id"], name: "index_results_{:column_options=>{:null=>true}}_on_generator_id"
I'm trying to get a nested form to work but keep getting the error below:
ActiveModel::MassAssignmentSecurity::Error in ResponsesController#create
Can't mass-assign protected attributes: gate_answer
Here are my models... what am I doing wrong?
class Response < ActiveRecord::Base
attr_accessible :gate_id, :gate_answers_attributes
belongs_to :gate
has_many :gate_answers
accepts_nested_attributes_for :gate_answers
end
class GateAnswer < ActiveRecord::Base
attr_accessible :prospect_id, :gate_question_id, :content, :response_id
belongs_to :response
end
And the DB schema extract:
create_table "gate_answers", :force => true do |t|
t.integer "prospect_id"
t.integer "gate_question_id"
t.text "content"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "response_id"
end
create_table "responses", :force => true do |t|
t.integer "gate_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
..and my controllers
# responses_controller.rb
def create
#response = Response.new(params[:response])
respond_to do |format|
if #response.save
format.html { redirect_to :action => 'index', :gate_id => (params[:response][:gate_id]), notice: 'Response was successfully created.' }
else
format.html { render action: "new" }
end
end
end
#gate_answers_controller.rb
def create
#gate_answer = GateAnswer.new(params[:gate_answer])
#code below finds URL that user will be redirected to after form is saved
#gate = Gate.find(params[:gate_answer][:gate_id])
respond_to do |format|
if #gate_answer.save
format.html { redirect_to #gate.content_url, notice: 'Redirecting.' } #redirect to URL per above
else
format.html { render action: "new" }
end
end
end
What am I doing wrong?
Try Form Object approach from here http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
A way of creating this type of form is shown in detail in the Railscasts Nested Model Form Part 1 & Part 2. Maybe this will help you?