I'm currently working on a project using Rails 3.2 and Active Scaffold. I've created a simple controller for one of my models that is coded thusly:
class StudentsController < ApplicationController
before_filter :authenticate_user!
active_scaffold :student do |conf|
conf.label = "Students"
conf.columns = [:last_name, :first_name, :age, :gender, :grade_level, :current_grade]
conf.create.columns = [:last_name, :first_name, :age, :gender, :grade_level]
conf.update.columns = [:last_name, :first_name, :age, :gender, :grade_level]
conf.columns[:current_grade].actions_for_association_links = [:show]
conf.columns[:current_grade].sort_by :sql => "grade_level"
conf.actions = [:list, :search, :create, :update, :show, :delete]
list.columns.exclude :customer_id, :grade_level
list.sorting = {:last_name => 'ASC'}
end
def conditions_for_collection
["customer_id = #{current_user.customer_id}"]
end
def before_create_save(record)
record.customer_id = current_user.customer_id
end
end
My problem is this: When I delete a record, I receive a message that states '$record_name can't be deleted'. Yet I find the record is in fact deleted if I refresh the page. Upon examining my log file I see an error message stating:
undefined method `as_marked=' for #<Student:0x0000000554c1d0>
I tried adding :mark to my list of actions and that does solve the problem. However, I don't want a mark/checkbox column to show up in my list.
Any ideas? This is my first time using active scaffold, and I find this... annoying.
I've discovered that if I add this to my model:
def as_marked= (x)
end
it works, without showing a mark/checkbox column in my list.
For the record, I hate this solution :) If I come up with anything better I'll make sure to come back and update this answer.
Related
I'm building a simple Rails-based travel app for a school project.
I want to make a form that enables the user to enter data such as the name of their Trip, two destinations, and each destination will have a location.
How can I do this with a triple nest form?
I'm very confused by the build method right now. Below is the def new method and the private methods in the controller.
class TripsController < ApplicationController
def new
#trip = Trip.new
Destination.all.each do |destination|
#trip.destinations.build.location
end
private
def set_trip
#trip = Trip.find(params[:id])
end
def trip_params
params.require(:trip).permit(:name, :start_date, :end_date,
:destination_1, :destination_2, :user_id, :destinations_attributes => [:name,
:locations_attributes => [:name]
]
)
Google pretty much answers this.
https://levelup.gitconnected.com/rails-nested-forms-in-three-steps-5580f0ad0e
https://guides.rubyonrails.org/form_helpers.html
You are looking for fields_for
I had a working Rails5.2 application that needed a database restructure to improve the organisation of some tables. Since this change, I've found that some of my forms fails consistently on my local machine with this error:
ActionController::InvalidAuthenticityToken in PayBandsController#create
I've had to change a lot in the application as part of the refactor, of course, but the tests are all passing.
I can avoid the issue by setting skip_before_action :verify_authenticity_token on the relevant controller (per previous SO threads) but this isn't a good fix, of course. I'd like to know what the root cause is and eliminate it.
The form works when it's on its own page, placed with render in the HTML.
The form works when I set the skip_before_action.
The form fails with an AuthenticityToken error otherwise - even though the same structure worked before.
This is all tested on my local machine with a valid session.
The form is created within a service object as the final line of a data table (so that I can add new lines to the table). Is this a potential cause of the problem - it's rendered in the service object rather than in the ERB? Although this approach worked fine before the refactor...
_table_data += ApplicationController.render(partial: 'datasets/pay_band_numbers_form', locals:{ _dataset_id: _dataset.id, _namespace: _key })
The partial is as follows and, as I said, works if placed on a page by itself (e.g. pay_bands/new) but not where it needs to be (on dataset/edit):
<%= form_for (PayBand.new), namespace: _namespace do |f| %>
<%= f.hidden_field :dataset_id, :value => _dataset_id %>
<%= f.text_field :label, :tabindex => 11, :required => true %>
<%= f.number_field :number_women, :tabindex => 12, :required => true %>
<%= f.number_field :number_men, :tabindex => 13, :required => true %>
<%= f.submit "β".html_safe, :tabindex => 14, class: "button green-button checkmark" %>
<% end %>
The models involved are Dataset and PayBand, which are defined as follows.
class Dataset < ApplicationRecord
belongs_to :organisation
has_many :pay_bands, inverse_of: :dataset, dependent: :destroy
accepts_nested_attributes_for :pay_bands
default_scope -> { order(created_at: :desc) }
validates :name, presence: true
validates :organisation_id, presence: true
end
class PayBand < ApplicationRecord
belongs_to :dataset
has_many :ages_salaries_genders, inverse_of: :pay_band, dependent: :destroy
validates :dataset_id, presence: true
validates :label, presence: true
end
The relevant parts of the dataset controller are:
class DatasetsController < ApplicationController
protect_from_forgery with: :exception
load_and_authorize_resource
before_action :authenticate_user!
.
.
.
def edit
#dataset = Dataset.find(params[:id])
end
def update
#dataset = Dataset.find(params[:id])
if #dataset.update_attributes(dataset_params) && dataset_params[:name]
flash[:notice] = "Survey updated"
redirect_back fallback_location: dataset_path(#dataset)
else
flash[:alert] = "Attempted update failed"
redirect_to edit_dataset_path(#dataset)
end
end
.
.
.
private
def dataset_params
params.require(:dataset).permit(:name)
end
end
The pay-band controller is:
class PayBandsController < ApplicationController
protect_from_forgery with: :exception
# skip_before_action :verify_authenticity_token #DANGEROUS!!!!!
load_and_authorize_resource
before_action :authenticate_user!
def create
#pay_band = PayBand.new(pay_band_params)
if #pay_band.save
flash[:notice] = "Data saved!"
redirect_to edit_dataset_path(Dataset.find(#pay_band.dataset_id))
else
flash[:alert] = "There was an error. Your data was not saved."
redirect_back fallback_location: edit_dataset_path(Dataset.find(pay_band_params[:dataset_id]))
end
end
private
def pay_band_params
params.require(:pay_band).permit(:label, :number_women, :number_men, :avg_salary_women, :avg_salary_men, :dataset_id)
end
end
All of the above controller structure is identical to the working version of the app, before I fiddled with the data models!
===
Edit
I decided to check the headers, after some more research, so see if I could see the token value. However, the token value in the meta csrf-token header tag doesn't match any of the 3 different tokens in the 3 different forms on this page. But one works anyway (the simple form that's just rendered in the ERB template) and the other two don't (the ones rendered in the service object). Which all leaves me just as confused as I was before!
Also, I tried removing Turbolinks from my GemFile and application.js file, re-running bundle and rails s, but it made no difference.
For future reference for anyone else having the same problem (AuthenticityToken errors for a form that's been built in a helper or service object), I moved the form directly into the view and rendered it there - and the problem disappeared. I've removed the skip_before_action :verify_authenticity_token and all is now well!
baby Ruby coder here.
I followed the steps here:https://masteruby.github.io/weekly-rails/2014/08/05/how-to-add-voting-to-rails-app.html#.XMFebOhKg2w to upload this act_as_votable gem however when I refresh my site to see if it works I get the following error: undefined method `acts_as_votable' for #<Class:0x00007f65df881b38>
The code does not seem to like the fact that I have put act_as_votable in my model I would like to use it on.
The error in my console also indicates that something is wrong in my controller. Do I need to define something there too?
Thanks in advance,
Angela
Model I want to use the act_as_votable gem on, you can see i have added it as the instructions instructed:
class Hairstyle < ApplicationRecord
belongs_to :user, optional: true
has_many :comments, dependent: :destroy
validates :name, presence: true
validates :description, presence: true
validates :category, presence: true
acts_as_votable
mount_uploader :photo, PhotoUploader
end
My hairstyles controller with the 'upvote' method at the end:
class HairstylesController < ApplicationController
def index
if params[:category].present?
#hairstyles = Hairstyle.where(category: params[:category])
elsif params[:search].present?
#hairstyles = Hairstyle.where('name ILIKE ?', '%#{params[:search]}%')
else
#hairstyles = Hairstyle.all
end
end
def show
#hairstyle = Hairstyle.find(params[:id])
#comment = Comment.new
end
def new
#hairstyle = Hairstyle.new
end
def create
#hairstyle = Hairstyle.create(hairstyle_params)
#hairstyle.user = current_user
if #hairstyle.save!
redirect_to hairstyle_path(#hairstyle)
else
render 'new'
end
end
def edit
#hairstyle = Hairstyle.find(params[:id])
end
def update
#hairstyle = Hairstyle.find(params[:id])
#hairstyle.update(hairstyle_params)
redirect_to hairstyles_path
end
def destroy
#hairstyle = Hairstyle.find(params[:id])
#hairstyle.destroy
redirect_to hairstyles_path
end
def upvote
#hairstyle = Hairstyle.find(params[:id])
#hairstyle.upvote_by current_user
redirect_to hairstyles_path
end
private
def hairstyle_params
params.require(:hairstyle).permit(:name, :description, :category, :location, :stylist, :photo, :video_url, :photo_cache)
end
end
My index file i'd like to display the gem on:
<% #hairstyles.each do |hairstyle| %>
<%= link_to "upvote", like_hairstyle_path(hairstyle), method: :put%>
<%end %>
</div>
Here is my repo if needed :https://github.com/Angela-Inniss/hair-do
It looks like you didn't run all 4 setup steps:
add 'acts_as_votable' to gemfile
Then run from terminal:
bundle install
rails generate acts_as_votable:migration
rake db:migrate
I cloned & setup your repo & I saw a few things going on that might be the cause:
The original error I got in this clone was due to act_as_taggable on your models. Your models should be annotated as acts_as_taggable (plural)
When I was initially testing, I wasn't logged in. This silently fails, which makes it seem like upvote isn't work. You might want to disable those hearts unless a user is logged in
Your html/erb template has some commented out code and such. This might be causing the link/URL to get swallowed and be non-clickable. I resolved it by deleting all styling & formatting except the link I was testing. I like using Haml to help reduce these kinds of nesting errors
I didn't run into your class error, but I would suggest running spring stop and trying to start your server again (I disable spring on all of my rails projects)
There is a Request model in my app. On different pages I need different validations, for example on /contacts I need to validate a lot of fields, whereas in a 'call me back later' popup I need to validate only phone number and name.
My problem is: data is saved, but without validations and type is not saved aswell.
Structure:
request.rb
class Request < ApplicationRecord
self.inheritance_column = :_type_disabled
def self.types
%w(ContactRequest CallMeBackRequest)
end
scope :contacts, -> { where(type: 'ContactRequest') }
scope :callmebacks, -> { where(type: 'CallMeBackRequest') }
end
routes.rb:
resources :contact_requests, only: [:new, :create], controller: 'requests', type: 'ContactRequest'
resources :call_me_back_requests, only: [:new, :create], controller: 'requests', type: 'CallMeBackRequest'
contact_request.rb:
class ContactRequest < Request
validates :name, :phone, :email, :company_name, presence: true
def self.sti_name
"ContactRequest"
end
end
call_me_back_request.rb:
class CallMeBackRequest < Request
validates :name, :phone, presence: true
def self.sti_name
"CallMeBack"
end
end
requests_controller.rb:
class Front::RequestsController < FrontController
before_action :set_type
def create
#request = Request.new(request_params)
respond_to do |format|
if #request.save
format.js
else
format.js { render partial: 'fail' }
end
end
end
private
def set_request
#request = type_class.find(params[:id])
end
def set_type
#type = type
end
def type
Request.types.include?(params[:type]) ? params[:type] : "Request"
end
def type_class
type.constantize
end
def request_params
params.require(type.underscore.to_sym).permit(Request.attribute_names.map(&:to_sym))
end
end
My form starts with:
=form_for Request.contacts.new, format: 'js', html: {class: 'g-contact__sidebar-right g-form'}, remote: true do |f|
I tried using ContactRequest.new - result was the same.
What I get when I hit the console:
Request.contacts.create!(name: "something") - does get saved, no validations are applied (why?). No type field is populated - why?
ContactRequest.create!(name: "something") - does not get saved, validations are applied
ContactRequest.create!(name: ..., all other required fields) - does get saved, but field type is empty - why?
Whatever I use for my form - ContactRequest.new or Request.contacts.new - neither validations are applied nor field type is set correctly.
Can anyone point me in the right direction? I'm mainly using this tutorial and other SO question, but without success.
Figured it out - since I'm not using the dedicated pages and paths for those contacts, i.e. contact_requests_path and corresponding new.html.haml, I need to pass the type parameter as a hidden field.
So my form now looks like this:
=form_for ContactRequest.new, format: 'js', html: {class: 'g-contact__sidebar-right g-form'}, remote: true do |f|
=f.hidden_field :type, value: "ContactRequest"
Considering validations - I don't know what I did, but after restarting the server a few times, they work now. The only this I remember really changing was the sti name here:
class CallMeBackRequest < Request
validates :name, :phone, presence: true
def self.sti_name
"CallMeBack" <- changed it from "CallMeBack" to "CallMeBackRequest"
end
end
I am attempting to locate a parent object in a nested controller, so that I can associate the descendant resource with the parent like so:
# teams_controller.rb <snippet only>
def index
#university = Univeresity.find(params[:university_id])
#teams = #university.teams
end
When I call find(params[:university_id]) per the snippet above & in line 6 of teams_controller.rb, I receive ActiveRecord::RecordNotFound - Couldn't find University without an ID.
I'm not only interested in fixing this issue, but would also enjoy a better understanding of finding objects without having to enter a University.find(1) value, since I grant Admin the privilege of adding universities.
The Rails Guides say the following about the two kinds of parameters in a website:
3 Parameters
You will probably want to access data sent in by the user or other
parameters in your controller actions. There are two kinds of
parameters possible in a web application. The first are parameters
that are sent as part of the URL, called query string parameters. The
query string is everything after β?β in the URL. The second type of
parameter is usually referred to as POST data. This information
usually comes from an HTML form which has been filled in by the user.
Itβs called POST data because it can only be sent as part of an HTTP
POST request. Rails does not make any distinction between query string
parameters and POST parameters, and both are available in the params
hash in your controller:
It continues a little further down, explaining that the params hash is an instance of HashWithIndifferentAccess, which allows usage of both symbols and strings interchangeably for the keys.
From what I read above, my understanding is that Rails recognizes both parameters (URL & POST) and stores them in the same hash (params).
Can I pass the params hash into a find method in any controller action, or just the create/update actions? I'd also be interested in finding a readable/viewable resource to understand the update_attributes method thats called in a controller's 'update' action.
Please overlook the commented out code, as I am actively searching for answers as well.
Thanks in advance.
Here are the associated files and server log.
Webrick
teams_controller.rb
class TeamsController < ApplicationController
# before_filter :get_university
# before_filter :get_team
def index
#university = University.find(params[:univeristy_id])
#teams = #university.teams
end
def new
#university = University.find(params[:university_id])
#team = #university.teams.build
end
def create
#university = University.find(params[:university_id])
#team = #university.teams.build(params[:team])
if #team.save
redirect_to [#university, #team], success: 'Team created!'
else
render :new, error: 'There was an error processing your team'
end
end
def show
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
end
def edit
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
end
def update
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
if #team.update_attributes(params[:team])
redirect_to([#university, #team], success: 'Team successfully updated')
else
render(:edit, error: 'There was an error updating your team')
end
end
def destroy
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
#team.destroy
redirect_to university_teams_path(#university)
end
private
def get_university
#university = University.find(params[:university_id]) # can't find object without id
end
def get_team
#team = #university.teams.find(params[:id])
end
end
team.rb
class Team < ActiveRecord::Base
attr_accessible :name, :sport_type, :university_id
has_many :home_events, foreign_key: :home_team_id, class_name: 'Event'
has_many :away_events, foreign_key: :away_team_id, class_name: 'Event'
has_many :medias, as: :mediable
belongs_to :university
validates_presence_of :name, :sport_type
# scope :by_university, ->(university_id) { where(team_id: team_id).order(name: name) }
# scope :find_team, -> { Team.find_by id: id }
# scope :by_sport_type, ->(sport_type) { Team.where(sport_type: sport_type) }
# scope :with_university, joins: :teams
# def self.by_university(university_id)
# University.where(id: 1)
# University.joins(:teams).where(teams: { name: name })
# end
def self.by_university
University.where(university_id: university_id).first
end
def self.university_join
University.joins(:teams)
end
def self.by_sport_type(sport_type)
where(sport_type: sport_type)
end
def self.baseball
by_sport_type('Baseball/Softball')
end
end
university.rb
class University < ActiveRecord::Base
attr_accessible :address, :city, :name, :state, :url, :zip
has_many :teams, dependent: :destroy
validates :zip, presence: true, format: { with: /\A\d{5}(-\d+)?\z/ },
length: { minimum: 5 }
validates_presence_of :name, :address, :city, :state, :url
scope :universities, -> { University.order(name: 'ASC') }
# scope :by_teams, ->(university_id) { Team.find_by_university_id(university_id) }
# scope :team_by_university, ->(team_id) { where(team_id: team_id).order(name: name)}
def sport_type
team.sport_type
end
end
views/teams/index.html.erb
Placed in gists for formatting reasons
rake routes output: (in a public gist)
enter link description here
rails console
You're not going to want to have both:
resources :universities #lose this one
resources :universities do
resources :teams
end
As for params... you have to give a param. So, when you go to http://localhost:3000/teams there are no params, by default. If you go to http://localhost:3000/teams/3 then params[:id] = 3 and this will pull up your third team.
Keep in mind the nomenclature of an index. The index action of Teams, is going to list all of the teams. All of them. There is no one University there, so what are you actually trying to find? If anything, you'd have, for your University controller:
def show
#university = University.find(params[:id])
#teams = #university.teams
end
so, the address bar will be showing http://localhost:3000/universities/23, right? params[:id] = 23, then you can find the teams associated with that university.