Passing Nil Value Through Link_to to controller value missing - ruby-on-rails-3

Updated
Per the answer below here is my new link_to
<%= link_to "Post a Question", new_classifieds_question_path(#classified) %>
and my controller
class QuestionsController < ApplicationController
def index
end
def new
#classified = Classified.find(params[:classified_id])
#question = Question.new
end
def create
#classified = Classified.find(params[:classified_id])
#question = Question.new(params[:question])
#classified.questions << #question
if #question.save
flash[:notice] = "Question has been posted"
else
flash[:notice] = "It did not go through"
end
end
end
new routes
resource :classifieds do
resources :questions
end
classified model
class Classified < ActiveRecord::Base
has_many :questions
end
and question model
class Question < ActiveRecord::Base
attr_accessible :question_body, :classifieds_id
belongs_to :classified
end
and my new error
Couldn't find Classified without an ID
I have a questions controller with two new/create methods
def new
#question = Question.new
end
def create
#question = Question.new(params[:question])
#question.classifieds_id = #classified.id
##question.classifieds_id = params[:id]
if #question.save
flash[:notice] = "Question has been posted"
else
flash[:notice] = "It did not go through"
end
end
A question belongs_to a classified ad. The questions table in the schema has a classifieds_id column.
Here is my question model
class Question < ActiveRecord::Base
attr_accessible :question_body, :classifieds_id
belongs_to :classified
end
in my routes.rb
resources :questions
Here is one variation of my link_to (in my show.html.erb)
This is my show method in another controller
def show
#classified=Classifieds.find(params[:id])
end
<td>
<%= link_to "Post a Question", new_question_path(#classified) %>
</td>
I am trying to pass the id of the classified instance to be processed by the questions controller.
I have tried many version of a link_to, like this
<td>
<%= link_to "Post a Question", new_question_path(:id => #classified.id) %>
</td>
and like this
<td><%= link_to "Post a Question", {:controller => "questions", :action => "new", :classified_id => #classified.id }, :class => "btn btn-default btn-lg" %></td>
<tr>
The hacks just isn't working and searching questions on stackoverflow isn't working either.
I have tried doing this in show.html.erb
<p>
<%= #classified.id %>
</p>
and the value gets outputted. I got better errors installed and a nil value gets passed in.
using gem 'rails', '3.2.13'

If you have nested resources in your routes...
resources :classifieds do
resources :questions
end
That will give you the method
<%= link_to "Post a question", new_classifieds_question_path(#classified) %>
Your new method will receive the classified_id
def new
#classified = Classified.find(params[:classified_id])
#question = Question.new
end
def create
#classified = Classified.find(params[:classified_id])
#question = Question.new(params[:question]
#classified.questions << #question
...
end
EDIT
Sorry, forgot the _path in the path call, now fixed.

Related

Limiting how often a user can post on a particular person's profile/wall in Rails

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] %>.

Nested resources link from index not working

Okay so I have a post index and would like to link it to my slide index, but for some reason i keep getting this error
No route matches {:controller=>"slides"}
when i link with this
<%= link_to 'Show Slides', post_slides_path(#post) %>
If i use the same link above in my Posts Edit Viewer, it seems to work fine....any suggestions?
I would basically like to link to this....../posts/:id/slides from the my table in posts
ROUTES.RB
resources :posts do
resources :slides
end
POST MODEL
class Post < ActiveRecord::Base
attr_accessible :text, :title
has_many :slides, :dependent => :destroy
def self.search(search)
if search
where('Title Like ?' , "%#{search}%")
else
scoped
end
end
SLIDE MODEL
class Slide < ActiveRecord::Base
belongs_to :post
POST INDEX VIEW
<table id="posts" class="table table-striped table-bordered">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= link_to 'Show Slides', post_slides_path(#post) %>
<td><%= link_to 'Edit', :action => :edit, :id => post.id %></td>
<td><%= link_to 'Destroy', { :action => :destroy, :id => post.id }, :method => :delete, :confirm => 'Are you sure?' %></td>
</tr>
<% end %>
<tbody>
<% end %>
</table>
POST CONTROLLER
class PostsController < ApplicationController
def new
#post = Post.new
end
def show
#post = Post.find(params[:id])
end
def index
#posts = Post.search(params[:search]).paginate(:per_page => 10, :page => params[:page])
end
def edit
#post = Post.find(params[:id])
end
SLIDE CONTROLLER
class SlidesController < ApplicationController
def index
#post = Post.find(params[:post_id])
#slides = #post.slides.all
end
def show
#post = Post.find(params[:post_id])
#slide = #post.slides.find(params[:id])
end
def new
#post = Post.find(params[:post_id])
#slide = Slide.new
end
def edit
#post = Post.find(params[:post_id])
#slide = Slide.find(params[:id])
end
The post_slides_path is looking for an id as the parameter to match to the /posts/:id/slides route. The reason it works in your edit page is because your #post variable is finding the id of the Post object ( #post = Post.find(params[:id]) ). In your index action of the Post controllers, you have the #posts instance variable pointing to the search params and paginating and you do not have a #post instance variable defined.
In your block try
post_slides_path(post.id)

Nested resources create Couldn't find Topic without an ID

I wanna make an application which User can create a topic and others can make posts after that. I nested my resources in my routes.rb:
MyPedia2::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :topics, only: [:show, :create, :destroy]
resources :posts
resources :topics do
resources :posts, only: [:create, :show, :new]
end
In my topic show page , I want to show topic.title and sended Posts and post.form.html.erb.
Everything works accept when i create a post , I get mistake
ActiveRecord::RecordNotFound in PostsController#create
Couldn't find Topic without an ID..
This is my posts_controller.rb:
class PostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
before_filter :correct_user, only: :destroy
def new
#topic= Topic.find_by_id(params[:id])
#post = #topic.posts.build(params[:post])
end
def show
#topic = Topic.find(params[:id])
#posts = #topic.posts.paginate(page: params[:page])
end
def create
#topic = Topic.find(params[:id])
#post = #topic.posts.build(params[:post])
#post.topic = #topic
if #post.save
flash[:success] = "Konu oluşturuldu!"
redirect_to :back
else
render 'static_pages/home'
end
end
def destroy
#post.destroy
redirect_to root_path
end
private
def correct_user
#post = current_user.posts.find_by_id(params[:id])
redirect_to root_path if #post.nil?
end
end
and _post_form.html.erb:
<%= form_for #new_post do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "yorumunuzu girin..." %>
</div>
<%= f.submit "Gönder", class: "btn btn-large btn-primary" %>
<% end %>
There are a few things that should solve things for you.
First and foremost, your create action in the posts controller is a bit wrong - it should look something like this:
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.build(params[:post])
# This is unnecessary as you're already adding
# the post to the topic with the build statement.
# #post.topic = #topic
if #post.save
flash[:success] = "Konu oluşturuldu!"
redirect_to :back
else
render 'static_pages/home'
end
end
This controller action assumes that you're going to use a put request to a post resource that is nested in topics, so you'll have to clean up your routes.
You have routes to posts#create both nested and unnested.
If posts are ALWAYS supposed to be nested within a topic, which your controller logic is stating, then you should add this to the unnested posts resource:
resources :posts, except: [:new, :create]
and then change that form_for tag to this:
<%= form_for [#topic, #post] do |f| %>
This tells the form builder that you're using a nested resource and will use the correct url for the http request.
Also - it looks like you're using loading all of your topics using Topic.find(params[:id]). This isn't going to work - you're in the posts controller, this is a post id. You should be loading posts with the id param like this: Post.find(params[:id]) and then the topic like this: topic = post.topic

Rails - Nested Model Fails to Save

I'm rather new to Rails and I'm writing a signup form that includes nested models. When I submit the form, the user is saved just fine, but the nested model does not save anything to the Subscription db, and the console throws no errors.
I sincerely hope I'm not missing something insanely obvious, and I appreciate any tips you can share. Thanks!
Here is the code-
Models:
class Plan < ActiveRecord::Base
attr_accessible :posts, :name, :price
has_many :users
end
class User < ActiveRecord::Base
belongs_to :plan
has_many :events
has_one :subscription, :autosave => true
accepts_nested_attributes_for :subscription
attr_accessible :subscription_attributes
def save_with_payment
if valid?
customer = Stripe::Customer.create(
email:email,
plan: plan_id,
card: stripe_card_token )
self.stripe_customer_token = customer.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
end
class Subscription < ActiveRecord::Base
attr_accessible :plan_id, :status, :user_id
belongs_to :user
end
This is the User controller:
def new
#user = User.new
plan = Plan.find(params[:plan_id])
#user = plan.user
#user.build_subscription
end
def create
#user = User.new(params[:user])
if #user.save_with_payment
sign_in #user
flash[:success] = "Welcome to the SendEvent!"
redirect_to #user
else
render 'new'
end
end
This is the form:
<%= form_for #user, :html => {:class => "form-inline"} do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="control-group">
<%= f.label :name, :class => "control-label" %>
<%= f.text_field :name %>
</div>
# A few more fields here and...
# The nested model:
<%= f.fields_for :subscription do |builder| %>
<%= builder.hidden_field :status, :value => true %>
<% end %>
<%= f.submit "Create my account", class: "btn btn-large btn-primary", id: "submitacct" %>
<% end %>
Sample app from RailsCasts
RailsCasts Episode #196: Nested Model Form (revised)
Maybe help you.

Calling two methods from one controller in nested model form

Through other posts on SO I've learned that my sign-up process using a nested model form is flawed in that I create a new User, then redirect to create its Profile. Here is the process:
user = User.new
user.email = ...
user.password = ...
user.profile = Profile.new
user.profile.first_name = ...
...
user.profile.save
user.save
It seems as if one solution is to initiate the profile method from within the UsersController create(?) action, so that I POST to both models(?) then redirect to a page with a form to fill out the rest of the profile.
But I'm not entirely sure how to do that, as I am new to programming/Rails. So can anyone give me guidance on how to introduce the Profile method within the UsersController? I gave it a go but don't think it's correct. Code for both Users/ProfilesController below:
User:
def new
#user = User.new
#user.profile = Profile.new
end
def index
#user = User.all
end
def create
#user = User.new(params[:user])
if #user.profile.save
redirect_to profile_new_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Profile:
def new
#user.profile = Profile.new
end
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Routes.rb:
match '/signup' => 'profiles#new', :as => "signup"
get "signup" => "profiles#new", :as => "signup"
root :to => 'users#new'
resources :users
resources :profiles
My nested model form (the relevant parts):
<%= form_for(:user, :url => { :action => :create }, :html => {:id => 'homepage'}) do |f| %>
<%= f.text_field :email, :size=> 13, :id => "user[email]" %>
<%= f.fields_for :profile do |f| %>
<% end%>
<% end %>
If anyone could help me I'd greatly appreciate it.
You should have something like this in your models:
class User < ActiveRecord::Base
has_one :profile
accepts_nested_attributes_for :profile
end
class Profile < ActiveRecord::Base
belongs_to :user
end
...of course all backed up with proper migrations. Then while building up a form you can use fields_for helper. Here is slightly modified example from docs:
<%= form_for #user do |user_form| %>
Email: <%= user_form.text_field :email %>
<%= user_form.fields_for :profile do |profile_fields| %>
First Name: <%= profile_fields.text_field :first_name %>
<% end %>
<% end %>
And update your user and his profile in the controller in one go, thanks to accepts_nested_attributes_for :profile declaration in your model.