Method should update attribute every time user click link_to. Accumulation belongs_to :user and :question
<%= link_to "+1", controller: "/accumulations", action: "vote_up",id: #question, user_id: current_user, method: "post" %>
def vote_up
#question = Question.find(params[:id])
#accumulation = Accumulation.where(user_id: current_user.id, question_id: #question.id )
Accumulation's 3rd attribute is point:
#accumulation.point = Accumulation.increment_counter(:point, #accumulation)
#accumulation.save
redirect_to :back, notice: "+1"
end
It gives me this message:
undefined method `point=' for # ActiveRecord::Relation:0xaa7fc10
How can I update attribute?
Assuming there is only one accumulation for any given user/question combo, you can add .first to your query:
#accumulation = Accumulation.where(user_id: current_user.id, question_id: #question.id ).first
Otherwise, you're trying to set point on a collection of records rather than an individual ActiveRecord object.
Related
I'm trying to make a form that you can only access once before a certain boolean is set to true, and along with it you input some other info, the problem is that I don't know how to set it up properly, so far the form loads no problem, but it doesn't update the information of the user.
my main problem is that I don't know how to set up the routes and the form, since most of the time I just use resources: to make them automatically
here is my form :
<%= form_for #user, url: organizer_user_path, method: :put do |f| %>
.
.
.
<%end%>
my routes, which I don't think put is correct at all
get 'organizer/user', to: "users#organizer_form"
put 'organizer/user', to: "users#organizer_registration"
and my controller
def organizer_form
#user = User.find(current_user[:id])
end
def organizer_registration
#user = User.find(current_user[:id])
if #user.update_attributes(user_params)
redirect_to #user
else
render 'organizer_form'
end
end
I'm sure the problem lies in how I define my routes and how they are called onto the form, any help?
here are the params that are submitted:
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
utf8: "✓"
_method: put
authenticity_token: w9zTUQLK+4kZtbvRCfcYfZgn8ma4xSRdbTMy+fktpoHlGADxHSB6u9QBh3K3zv72V/Ys2b3Q1MiKC0Gr+OqNJw==
user: !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
organizer: 'true'
contact_name: Name
last_name: Last name
contact_email: mail1#mail.com
cellphone: '1234567'
company: ''
office_phone: ''
website: ''
permitted: false
commit: continuar
controller: users
action: organizer_registration
permitted: false
This is my user_params
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation, :organizer, :contact_name, :last_name, :contact_email, :cellphone, :company, :office_phone, :website)
end
Finally found the answer! I had
attr_accessor :organizer, :contact_name, :last_name, :contact_email, :cellphone, :company, :office_phone, :website
which somehow stopped the update from happening, so removing that made the updates save to the database.
I am developing a web application with Rails in which I need to save two models with the same form. One of the models (Characteristic) belongs to the other (Facilities), so I decided to use a accepts_nested_attributes_for for the contained model. In the view, I use form_for to save the parent model (Characteristic) and another form_for for the contained model (Facilities). However, I always obtain the same error:
Started PUT "/facilities/537f8adfb4f2d7c124000056" for 127.0.0.1 at 2014-05-31 20:00:23 +0200
Processing by FacilitiesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xr+cGlb9onx4o13IaS3K5UfYzmrb6pMdKljBc8byKdY=", "facilities"=>{"description"=>"Services", "characteristics"=>[{"id"=>"537f8adfb4f2d7c124000057", "title"=>"Room", "description"=>"Free"}]}, "commit"=>"Send", "id"=>"537f8adfb4f2d7c124000056"}
MOPED: 127.0.0.1:27017 COMMAND database=admin command={:ismaster=>1} (1.2872ms)
MOPED: 127.0.0.1:27017 QUERY database=hotel_abadi_development collection=facilities selector={"_id"=>"537f8adfb4f2d7c124000056"} flags=[:slave_ok] limit=0 skip=0 batch_size=nil fields=nil (0.4916ms)
MOPED: 127.0.0.1:27017 QUERY database=hotel_abadi_development collection=admins selector={"$query"=>{"_id"=>"537f8ad9b4f2d7c124000001"}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields=nil (0.7987ms)
MOPED: 127.0.0.1:27017 QUERY database=hotel_abadi_development collection=admins selector={"$query"=>{"_id"=>"537f8ad9b4f2d7c124000001"}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields=nil (0.7885ms)
MOPED: 127.0.0.1:27017 QUERY database=hotel_abadi_development collection=facilities selector={"$query"=>{"admin_id"=>"537f8ad9b4f2d7c124000001"}, "$orderby"=>{:_id=>1}} flags=[:slave_ok] limit=-1 skip=0 batch_size=nil fields=nil (0.8206ms)
Completed 500 Internal Server Error in 502.0ms
NoMethodError (undefined method `id' for #<ActiveSupport::HashWithIndifferentAccess:0xa6ae334>):
app/controllers/facilities_controller.rb:21:in `update'
Rendered /home/jesus/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-3.2.15/lib/action_dispatch/middleware/templates/rescues/_trace.erb (2.5ms)
Rendered /home/jesus/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-3.2.15/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.4ms)
Rendered /home/jesus/.rvm/gems/ruby-2.0.0-p353/gems/actionpack-3.2.15/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (17.7ms)
In order to solve the problem, I have also tried to use fields_for with the nested attributes but I obtain the same error. The main files which defines the application are the next:
app/models/facilities.rb
class Facilities
...
field :description, type: String
field :language, type: Symbol, default: :es
has_many :characteristics, dependent: :destroy
accepts_nested_attributes_for :characteristics, allow_destroy: true
...
end
app/models/characteristic.rb
class Characteristic
...
field :title, type: String
field :description, type: String
field :language, type: Symbol, default: :es
belongs_to :admin
has_one :upload, dependent: :destroy
accepts_nested_attributes_for :upload, allow_destroy: true
...
end
app/controllers/facilities_controller.rb
class FacilitiesController < ApplicationController
load_and_authorize_resource
respond_to :json, :html
...
def update
#facilities.update_attributes!( params[:facilities] )
respond_with #facilities, api_template: :general, location: hotel_path
end
...
end
app/views/facilities.html.haml
= form_for facilities, url: facilities_path( facilities ) do |f|
= f.text_area :description
.facilities_form
- facilities.characteristics.each_with_index do |char, index|
= form_for characteristic, url: characteristic_path( characteristic ), html: { method: :put } do |d|
= d.hidden_field :id, name: 'facilities[characteristics][][id]'
= d.text_field :title, width: 20, size: 20, name: 'facilities[characteristics][][title]'
= d.text_area :description, width: 20, rows: 4, cols: 22, name: 'facilities[characteristics][][description]'
= f.submit "Send"
Solved:
In the nested attributes, I manually put the name of the fields because I am using another form_for for them. In that names, I use "facilities[characteristics][][name_of_field]", but when we need to use nested attributes, we have to put "characteristics_attributes", so the correct name is "facilities[characteristics_attributes][][name_of_field]".
I've spotted that you use facilities instead of facility both in view and controller.
I assume the problem is load_and_authorize_resource in FacilitiesController try to load #facility extracting id from params. So, change facilities_path( facilities ) to facilities_path(#facility) or something similar.
How can I limit a user to only to being able to post once or twice per day on a particular users's wall? I primarily want to do it in order to limit spam. My code for the wall, models, view, and controllers are below. I don't really know how to go about it as I'm new to rails but I know there is something time.now. I'm not exactly sure how to implement such a feature.
Class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#first_name = #user.first_name
#last_name = #user.last_name
#wallpost = WallPost.new(params[:wall_post])
#showwallposts = #user.received_wallposts
end
def create
#wallpost = WallPost.create(params[:wall_post])
end
models
class WallPost < ActiveRecord::Base
attr_accessible :content, :receiver_id, :sender_id
belongs_to :receiver, :class_name => "User", :foreign_key => "receiver_id"
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
end
class User < ActiveRecord::Base
has_many :sent_wallposts, :class_name => 'WallPost', :foreign_key => 'sender_id'
has_many :received_wallposts, :class_name =>'WallPost', :foreign_key => 'receiver_id'
in the view
<%= form_for(#wallpost, :url => {:action => 'create'}) do |f| %>
<%= f.hidden_field :receiver_id, :value => #user.id %>
<%= f.hidden_field :sender_id, :value => current_user.id %>
<%= f.text_area :content, :class => 'inputbox' %>
<%= f.submit 'Post', class: 'right btn' %>
<% end %>
You could create a custom validator which assures maximum DAILY_LIMIT posts have been created on that person's wall that day by that user:
class SpamValidator < ActiveModel::Validator
DAILY_LIMIT = 2
def validate(record)
if similar_posts_today(record).count >= DAILY_LIMIT
record.errors[:spam_limit] << 'Too many posts today!'
end
end
def similar_posts_today(record)
WallPost.where(receiver: record.receiver, sender: record.sender)
.where("DATE(created_at) = DATE(:now)", now: Time.now)
end
end
Then add that validation to your WallPost model:
validates_with SpamValidator
Then it will fail with a validation error when trying to create a wall post beyond the limit set in the constant. You need to handle this case in the create action in your controller. A simple (but not optimal in terms of user experience) way of handling this is:
def create
#wallpost = WallPost.new(params[:wall_post])
flash[:error] = "You've reached the daily posting limit on that wall." unless #wallpost.save
redirect_to user_path(#wallpost.receiver)
end
With that, it'll try to save the new wall post, if it is unable to, it'll set flash[:error] to the error message above. You'd need to show this on your show.html.erb page with <%= flash[:error] if flash[:error] %>.
I'm trying to build up on the following tutorial from railscast:
http://railscasts.com/episodes/196-nested-model-form-part-1
I'm trying to make everything work with mongodb and mongoid.
the scenario is:
I want to creates events linked to a location. Each events (dance class) contains many lessons.
So I thought that an embedded relationship would be perfect.
Here are my models
model Lesson
class Lesson
include Mongoid::Document
include Mongoid::Slug
field :name, :type => String
embedded_in :event
slug :name
end
model Event
class Event
include Mongoid::Document
include Mongoid::Slug
include Mongoid::Timestamps
include Mongoid::MultiParameterAttributes
field :name, :type => String
field :description, :type => String
field :date, :type => DateTime
validates_presence_of :name
has_one :venue
referenced_in :venue
embeds_many :lessons
slug :name
end
model Venue
class Venue
include Mongoid::Document
include Mongoid::Slug
include Mongoid::Timestamps
include Mongoid::MultiParameterAttributes
field :name, :type => String
field :location, :type => String
validates_presence_of :name, :location
belongs_to :event
slug :name
end
event controller
def create
#event = Event.new(params[:event])
if #event.save
flash[:notice] = 'Event was successfully created.'
end
respond_with(#Event, :location => events_url)
end
def update
# #event = Event.find(params[:id])
#event = Event.find_by_slug(params[:id])
if #event.update_attributes(params[:event])
flash[:notice] = "Event was succesfully updated"
end
respond_with(#event)
end
Then I have my Event view where I can create events and link it to a Venue. But I'd like to be abe to create the lessons from the Event view/model.
so I used the fields_for to generate a field linked to the Lessons model.
= form_for #event do |f|
.field
= f.label :name
%br/
= f.text_field :name
.field
= f.label :description
%br/
= f.text_area :description
.field
= f.label :venue_id
%br/
= f.collection_select :venue_id, Venue.all, :id, :name
.field
= f.label :date
%br/
= f.datetime_select :date
%h3 Add a Class
= f.fields_for :lessons do |builder|
= render "lesson_fields", :f => builder
.actions
= f.submit 'Save'
When I create or edit a new event I get an error message:
undefined method `extract_id' for "test":String
But the request parameter message on the error page shows my lessons value in the Event document.
"lessons"=>{"name"=>"test name lesson"}
When I remove the fields_for line, everything works fine. But then i don't know how to save the value for the nested documents.
I have same problem with embeds_many, but when i try change to has_many. It works!. Maybe you can try too.
can you post the exact code you use to create the Event, including parameters?
which version of Mongoid and Rails are you using?
First thing I noticed is that the following parameter hash does not match your Lessons model:
"lessons"=>{"content"=>"test name lesson"} # this looks wrong
this should be:
"lessons"=>{"name" => "test name lesson"}
Looks like your lessons form has the wrong label for the text input field .. it should be :name , not :content
To dry things up, you might want to try if the 'nested_form' gem works for you:
after installing the gem, use the nested_form_for instead of form_for in your view.
Check here for a more detailed description:
How can I handle this type of multi level forms in rails
See:
https://github.com/ryanb/nested_form (it's also referenced in the RailsCast you mentioned)
You also might want to check this:
field_for and nested form with mongoid
The conclusion of this story is...
I removed everything related to mongoid_slug and it started to work.
I then put everything back as it was to try to find out how to make it work with mongoid_slug and it just worked, like out of the box.
:(
Please include the following code in model event.rb
**accepts_nested_attributes_for :lessons**
This will fix your problem
I have question model which has many options.
In my question controller new action I create five options ready for my user
def new
#question = Question.new
5.times.with_index do |index|
#question.options.build(:order => index)
end
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #question }
end
end
In the view I loop through all options
- form_for(#question) do |f|
.field
= f.label :title, t("question.title")
= show_errors_for(#question, :title)
= f.text_field :title
- #question.options.each do |option|
- f.fields_for :options, option do |o|
.field
= o.label :option, t("question.option_no", { :index => option.order })
= o.text_field :option
= o.hidden_field :order, :value => option.order
.actions
= f.submit t("add_question.create")
My question model looks like this
class Question < ActiveRecord::Base
attr_accessible :title, :options_attributes
belongs_to :user
has_many :options
accepts_nested_attributes_for :options, :reject_if => proc { |attributes| attributes['option'].blank? }
validates :title, :length => { :maximum => 100 }, :presence => true
validate :min_no_of_options
def min_no_of_options
if self.options.size < 3
errors.add_to_base "Must have at least three options"
end
end
end
And my question controller create action
def create
if current_user
#question = current_user.questions.build(params[:question])
else
#question = Question.new(params[:question])
end
if #question.save
redirect_to(#question, :success => t('question.flash_success'))
else
flash.now[:error] = t("question.flash_error")
render :action => "new"
end
end
Now, when I enter only two options in the form and hit the create button the validation prevents the model from being saved. Which is good. But when the create action renders the new action again, only the option fields that I filled are showing up. The three option fields which were left blank have disappeared.
If I replace the "#question.save" in my create action with "false", the behavior is the same. So this suggests that something in the way I create the #question variable in the create action is responsible for throwing away my empty options.
But if I instead remove the :reject_if from my question model the empty options are showing up after a failing question save as expected. (I have a presence validation for the option attribute in my option model) So this tells me that there is nothing wrong in the way I create the #question variable in the create action. It is not throwing away the empty options. So where they are kicked out?
There was one pretty similar question, but the answer in there is not something I would like to do. Though it might be something I have to do.
rails fields_for does not render after validation error on nested form
EDIT
After some more study with rails console I noticed that it truly is the creation of #question variable where the empty options get thrown away. This happens because I have the reject_if defined in the question model. After commenting the reject_if out from the model the empty options were added into the #question variable.
So I guess I need to remove the reject_if and use after_save callback to destroy empty options from the database. This way I will have the empty options going along with the question until the question is saved.
I'm answering my own question because I got the issue solved.
Blank "options" were removed from the "question" because of reject_if in the "question" model. The reject_if statement was applied when the code below was executed, and therefore blank "options" were removed.
#question = current_user.questions.build(params[:question])
I replaced the reject_if with an after_save callback which removes the options which were left blank.